├── src ├── includes │ ├── templates │ │ ├── htaccess │ │ │ ├── back-compat │ │ │ │ ├── v151114-2.txt │ │ │ │ └── v151114.txt │ │ │ ├── browser-caching-enable.txt │ │ │ ├── access-control-allow-origin-enable.txt │ │ │ ├── enforce-exact-host-name.txt │ │ │ ├── gzip-enable.txt │ │ │ ├── canonical-urls-no-ts-enable.txt │ │ │ └── canonical-urls-ts-enable.txt │ │ └── ac-plugin.txt │ ├── traits │ │ ├── Plugin │ │ │ ├── DbUtils.php │ │ │ ├── CondUtils.php │ │ │ ├── HtmlCUtils.php │ │ │ ├── CdnUtils.php │ │ │ ├── ActionUtils.php │ │ │ ├── WcpJetpackUtils.php │ │ │ ├── CleanupUtils.php │ │ │ ├── WcpPluginUtils.php │ │ │ ├── .build.php │ │ │ ├── PostUtils.php │ │ │ ├── StatsUtils.php │ │ │ ├── UrlUtils.php │ │ │ ├── WcpS2cleanUtils.php │ │ │ ├── WcpEvalUtils.php │ │ │ ├── WcpWooCommerceUtils.php │ │ │ ├── WcpSettingUtils.php │ │ │ ├── WcpCdnUtils.php │ │ │ ├── BbPressUtils.php │ │ │ ├── WcpSitemapUtils.php │ │ │ ├── WcpUrlUtils.php │ │ │ ├── WcpOpcacheUtils.php │ │ │ ├── WcpPostTypeUtils.php │ │ │ ├── DirUtils.php │ │ │ ├── OptionUtils.php │ │ │ ├── WcpCommentUtils.php │ │ │ ├── WcpHomeBlogUtils.php │ │ │ ├── CronUtils.php │ │ │ └── WcpDateArchiveUtils.php │ │ ├── Ac │ │ │ ├── AbortUtils.php │ │ │ ├── ShutdownUtils.php │ │ │ ├── AcPluginUtils.php │ │ │ ├── .build.php │ │ │ ├── ClientSideUtils.php │ │ │ └── HtmlCUtils.php │ │ └── Shared │ │ │ ├── EscapeUtils.php │ │ │ ├── ArrayUtils.php │ │ │ ├── .build.php │ │ │ ├── TrimUtils.php │ │ │ ├── I18nUtils.php │ │ │ ├── PatternUtils.php │ │ │ ├── BlogUtils.php │ │ │ ├── ReplaceUtils.php │ │ │ ├── ServerUtils.php │ │ │ ├── SysUtils.php │ │ │ ├── CacheLockUtils.php │ │ │ ├── IpAddrUtils.php │ │ │ ├── MemoryUtils.php │ │ │ └── UrlUtils.php │ ├── api.php │ ├── uninstall.php │ ├── plugin.php │ ├── classes │ │ ├── MenuPage.php │ │ ├── MenuPage │ │ │ └── Options │ │ │ │ ├── Directory.php │ │ │ │ ├── Safeguards.php │ │ │ │ ├── FeedRequests.php │ │ │ │ ├── ImportExport.php │ │ │ │ ├── HostExclusions.php │ │ │ │ ├── Developers.php │ │ │ │ ├── UserAgentExclusions.php │ │ │ │ ├── RefererExclusions.php │ │ │ │ ├── UriExclusions.php │ │ │ │ └── Nf404Requests.php │ │ ├── AbsBaseAp.php │ │ ├── AdvancedCache.php │ │ ├── Notes.php │ │ ├── AdvCacheBackCompat.php │ │ ├── MenuPageOptions.php │ │ └── Conflicts.php │ ├── functions │ │ ├── i18n-utils.php │ │ └── wp-cache-postload.php │ ├── stub.php │ └── interfaces │ │ └── Shared │ │ └── CachePathConsts.php ├── client-s │ ├── css │ │ ├── menu-pages │ │ │ ├── _html-tag.scss │ │ │ ├── _body.scss │ │ │ ├── _sections.scss │ │ │ ├── _save.scss │ │ │ ├── _wpwrap.scss │ │ │ ├── _animations.scss │ │ │ ├── _colors.scss │ │ │ ├── _heading.scss │ │ │ └── _panels.scss │ │ ├── admin-bar.scss │ │ ├── menu-pages.scss │ │ └── admin-bar │ │ │ ├── _animations.scss │ │ │ ├── _ajax-response.scss │ │ │ └── _wipe-clear.scss │ └── images │ │ ├── bg.png │ │ ├── clear.png │ │ ├── gzip.png │ │ ├── salt.png │ │ ├── stats.png │ │ ├── tach.png │ │ ├── wipe.png │ │ ├── apache.png │ │ ├── opcache.png │ │ ├── spinner.png │ │ ├── keycdn-logo.png │ │ ├── maxcdn-logo.png │ │ ├── options-lite.png │ │ ├── options-pro.png │ │ ├── pro-updater.png │ │ ├── auto-clear-ss.png │ │ ├── clear-response.png │ │ ├── cloudfront-logo.png │ │ ├── source-code-ss.png │ │ ├── stats-fc-empty.png │ │ ├── stats-fs-empty.png │ │ ├── stats-preview.png │ │ ├── wipe-response.png │ │ ├── clear-cache-ops0-ss.png │ │ ├── clear-cache-ops1-ss.png │ │ ├── clear-cache-ops2-ss.png │ │ └── inline-icon.svg └── .htaccess ├── .gitmodules ├── .gitchange ├── tests ├── includes │ ├── casperjs.js │ └── phpunit.php ├── phpunit │ └── ActiveTest.php ├── casperjs │ └── ActiveTest.js └── local │ └── browscap.php ├── uninstall.php ├── comet-cache-pro.php ├── README.md ├── .travis.bash ├── .travis.yml ├── .gitignore ├── .build.props └── composer.json /src/includes/templates/htaccess/back-compat/v151114-2.txt: -------------------------------------------------------------------------------- 1 | # BEGIN ZenCache 2 | # END ZenCache 3 | -------------------------------------------------------------------------------- /src/client-s/css/menu-pages/_html-tag.scss: -------------------------------------------------------------------------------- 1 | html { 2 | overflow-y: scroll; 3 | } 4 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "phings"] 2 | path = phings 3 | url = https://github.com/websharks/phings.git 4 | -------------------------------------------------------------------------------- /src/client-s/images/bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wpsharks/comet-cache-pro/HEAD/src/client-s/images/bg.png -------------------------------------------------------------------------------- /src/client-s/css/menu-pages/_body.scss: -------------------------------------------------------------------------------- 1 | .plugin-menu-page-body { 2 | position: relative; 3 | } 4 | -------------------------------------------------------------------------------- /src/client-s/images/clear.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wpsharks/comet-cache-pro/HEAD/src/client-s/images/clear.png -------------------------------------------------------------------------------- /src/client-s/images/gzip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wpsharks/comet-cache-pro/HEAD/src/client-s/images/gzip.png -------------------------------------------------------------------------------- /src/client-s/images/salt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wpsharks/comet-cache-pro/HEAD/src/client-s/images/salt.png -------------------------------------------------------------------------------- /src/client-s/images/stats.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wpsharks/comet-cache-pro/HEAD/src/client-s/images/stats.png -------------------------------------------------------------------------------- /src/client-s/images/tach.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wpsharks/comet-cache-pro/HEAD/src/client-s/images/tach.png -------------------------------------------------------------------------------- /src/client-s/images/wipe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wpsharks/comet-cache-pro/HEAD/src/client-s/images/wipe.png -------------------------------------------------------------------------------- /src/client-s/images/apache.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wpsharks/comet-cache-pro/HEAD/src/client-s/images/apache.png -------------------------------------------------------------------------------- /src/client-s/images/opcache.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wpsharks/comet-cache-pro/HEAD/src/client-s/images/opcache.png -------------------------------------------------------------------------------- /src/client-s/images/spinner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wpsharks/comet-cache-pro/HEAD/src/client-s/images/spinner.png -------------------------------------------------------------------------------- /src/client-s/images/keycdn-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wpsharks/comet-cache-pro/HEAD/src/client-s/images/keycdn-logo.png -------------------------------------------------------------------------------- /src/client-s/images/maxcdn-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wpsharks/comet-cache-pro/HEAD/src/client-s/images/maxcdn-logo.png -------------------------------------------------------------------------------- /src/client-s/images/options-lite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wpsharks/comet-cache-pro/HEAD/src/client-s/images/options-lite.png -------------------------------------------------------------------------------- /src/client-s/images/options-pro.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wpsharks/comet-cache-pro/HEAD/src/client-s/images/options-pro.png -------------------------------------------------------------------------------- /src/client-s/images/pro-updater.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wpsharks/comet-cache-pro/HEAD/src/client-s/images/pro-updater.png -------------------------------------------------------------------------------- /src/client-s/images/auto-clear-ss.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wpsharks/comet-cache-pro/HEAD/src/client-s/images/auto-clear-ss.png -------------------------------------------------------------------------------- /src/client-s/images/clear-response.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wpsharks/comet-cache-pro/HEAD/src/client-s/images/clear-response.png -------------------------------------------------------------------------------- /src/client-s/images/cloudfront-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wpsharks/comet-cache-pro/HEAD/src/client-s/images/cloudfront-logo.png -------------------------------------------------------------------------------- /src/client-s/images/source-code-ss.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wpsharks/comet-cache-pro/HEAD/src/client-s/images/source-code-ss.png -------------------------------------------------------------------------------- /src/client-s/images/stats-fc-empty.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wpsharks/comet-cache-pro/HEAD/src/client-s/images/stats-fc-empty.png -------------------------------------------------------------------------------- /src/client-s/images/stats-fs-empty.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wpsharks/comet-cache-pro/HEAD/src/client-s/images/stats-fs-empty.png -------------------------------------------------------------------------------- /src/client-s/images/stats-preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wpsharks/comet-cache-pro/HEAD/src/client-s/images/stats-preview.png -------------------------------------------------------------------------------- /src/client-s/images/wipe-response.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wpsharks/comet-cache-pro/HEAD/src/client-s/images/wipe-response.png -------------------------------------------------------------------------------- /src/client-s/images/clear-cache-ops0-ss.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wpsharks/comet-cache-pro/HEAD/src/client-s/images/clear-cache-ops0-ss.png -------------------------------------------------------------------------------- /src/client-s/images/clear-cache-ops1-ss.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wpsharks/comet-cache-pro/HEAD/src/client-s/images/clear-cache-ops1-ss.png -------------------------------------------------------------------------------- /src/client-s/images/clear-cache-ops2-ss.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wpsharks/comet-cache-pro/HEAD/src/client-s/images/clear-cache-ops2-ss.png -------------------------------------------------------------------------------- /.gitchange: -------------------------------------------------------------------------------- 1 | 1491589996 2 | 2ea258a033ce686450ef6bccbc0f66efdba74ac1:58ffb9673670b6.69941207 3 | d0e05c36184f81b133761b71ca6ee0136be67409:5928a421a111c6.72961003 4 | -------------------------------------------------------------------------------- /src/includes/templates/htaccess/browser-caching-enable.txt: -------------------------------------------------------------------------------- 1 | # Enable browser caching. 2 | FileETag mtime size 3 | 4 | 5 | ExpiresActive on 6 | ExpiresDefault "access plus 1 week" 7 | 8 | -------------------------------------------------------------------------------- /tests/includes/casperjs.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Bootstrap. 3 | */ 4 | $$$ = { 5 | SHORT_NAME: 'CC', 6 | NAME: 'Comet Cache', 7 | DOMAIN: 'cometcache.com', 8 | GLOBAL_NS: 'comet_cache', 9 | SLUG_TD: 'comet-cache' 10 | }; 11 | -------------------------------------------------------------------------------- /tests/includes/phpunit.php: -------------------------------------------------------------------------------- 1 | 3 | 4 | Header set Access-Control-Allow-Origin "*" 5 | 6 | 7 | # END ZenCache 8 | -------------------------------------------------------------------------------- /uninstall.php: -------------------------------------------------------------------------------- 1 | 3 | 4 | Header set Access-Control-Allow-Origin "*" 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/client-s/css/menu-pages/_sections.scss: -------------------------------------------------------------------------------- 1 | .plugin-menu-page-section-heading { 2 | margin: 1em; 3 | 4 | > small { 5 | margin: 0; 6 | font-size: 65%; 7 | font-style: italic; 8 | display: block; 9 | opacity: 0.5; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /tests/phpunit/ActiveTest.php: -------------------------------------------------------------------------------- 1 | plugin = $GLOBALS[GLOBAL_NS]; 9 | } 10 | 11 | public function testActive() 12 | { 13 | $this->assertSame(true, (bool) $this->plugin->options['enable']); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/.htaccess: -------------------------------------------------------------------------------- 1 | 2 | Require all denied 3 | 4 | 5 | deny from all 6 | 7 | 8 | 9 | 10 | Require all granted 11 | 12 | 13 | allow from all 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/includes/traits/Plugin/DbUtils.php: -------------------------------------------------------------------------------- 1 | isAutoCacheEngine()) { 17 | ignore_user_abort(true); 18 | } 19 | /*[/pro]*/ 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/includes/uninstall.php: -------------------------------------------------------------------------------- 1 | uninstall(); 21 | } 22 | -------------------------------------------------------------------------------- /src/client-s/css/menu-pages/_wpwrap.scss: -------------------------------------------------------------------------------- 1 | #wpwrap { 2 | position: relative; 3 | 4 | &::after { 5 | top: 0; 6 | right: 0; 7 | bottom: 0; 8 | left: 0; 9 | z-index: -1; 10 | position: absolute; 11 | content: ''; 12 | opacity: 0.25; 13 | background: url('../images/bg.png'); 14 | } 15 | 16 | .updated, 17 | .error { 18 | margin: 1.25em 1.25em 1.25em 0.25em; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /tests/casperjs/ActiveTest.js: -------------------------------------------------------------------------------- 1 | $.test.begin('Check if plugin is active.', function () { 2 | $.start(); 3 | $$.wp.thenLogin(); 4 | 5 | if ($$.wp.isMultisite()) { 6 | $.thenOpen($$.www.url('/wp-admin/network/admin.php?page=' + $$$.GLOBAL_NS)); 7 | } else { 8 | $.thenOpen($$.www.url('/wp-admin/admin.php?page=' + $$$.GLOBAL_NS)); 9 | } 10 | $.then(function () { 11 | $.test.assertExists('input[type="radio"][name="' + $$$.GLOBAL_NS + '[saveOptions][enable]"][value="1"]:checked'); 12 | }); 13 | $$.wp.thenLogout(); 14 | 15 | $.run(function () { 16 | $.test.done(); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /src/client-s/css/menu-pages/_animations.scss: -------------------------------------------------------------------------------- 1 | // Animation :: spin. 2 | 3 | @mixin plugin-menu-page-animation-spin { 4 | @include animation-duration(0.75s); 5 | @include animation-fill-mode(both); 6 | @include animation-timing-function(linear); 7 | @include animation-iteration-count(infinite); 8 | @include animation-name(plugin-menu-page-animation-spin); 9 | } 10 | 11 | .plugin-menu-page-animation-spin { 12 | @include plugin-menu-page-animation-spin; 13 | } 14 | 15 | @include keyframes(plugin-menu-page-animation-spin) { 16 | 0% { 17 | @include transform(rotate(0deg)); 18 | } 19 | 20 | 100% { 21 | @include transform(rotate(360deg)); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/includes/plugin.php: -------------------------------------------------------------------------------- 1 | options['enable']) { 20 | return; // Nothing to do. 21 | } 22 | echo "\n".''."\n"; 23 | } 24 | } 25 | /*[/pro]*/ 26 | -------------------------------------------------------------------------------- /src/includes/templates/htaccess/enforce-exact-host-name.txt: -------------------------------------------------------------------------------- 1 | # Enforce exact host name. 2 | 3 | RewriteEngine on 4 | RewriteBase %%REWRITE_BASE%% 5 | 6 | RewriteCond %{HTTP_HOST} !^%%HOST_NAME_AS_REGEX_FRAG%%$ 7 | RewriteCond %{HTTPS} !^on$ [NC] 8 | RewriteCond %{HTTP:X-Forwarded-Proto} !^https$ [NC] 9 | RewriteRule .* http://%%HOST_NAME_AS_REGEX_FRAG%%%{REQUEST_URI} [R=301,L] 10 | 11 | RewriteCond %{HTTP_HOST} !^%%HOST_NAME_AS_REGEX_FRAG%%$ 12 | RewriteCond %{HTTPS} ^on$ [NC,OR] 13 | RewriteCond %{HTTP:X-Forwarded-Proto} ^https$ [NC] 14 | RewriteRule .* https://%%HOST_NAME_AS_REGEX_FRAG%%%{REQUEST_URI} [R=301,L] 15 | 16 | -------------------------------------------------------------------------------- /src/client-s/css/menu-pages.scss: -------------------------------------------------------------------------------- 1 | @import '../../vendor/package/bourbon/bourbon-v4.2.3/bourbon'; 2 | 3 | @import '../../vendor/websharks/sharkicons/src/sharkicons'; 4 | @include sharkicons-font('../../vendor/websharks/sharkicons/src'); 5 | @include sharkicon-short-classes; 6 | 7 | @import 'menu-pages/colors'; 8 | @import 'menu-pages/animations'; 9 | @import 'menu-pages/html-tag'; 10 | @import 'menu-pages/wpwrap'; 11 | @import 'menu-pages/elements'; 12 | @import 'menu-pages/heading'; 13 | @import 'menu-pages/body'; 14 | @import 'menu-pages/sections'; 15 | @import 'menu-pages/panels'; 16 | @import 'menu-pages/save'; 17 | 18 | /*![pro strip-from='lite']*/ 19 | @import 'menu-pages/stats'; 20 | /*![/pro]*/ 21 | -------------------------------------------------------------------------------- /src/includes/templates/htaccess/gzip-enable.txt: -------------------------------------------------------------------------------- 1 | # Enable GZIP compression. 2 | 3 | 4 | AddOutputFilterByType DEFLATE text/plain text/html 5 | AddOutputFilterByType DEFLATE text/xml application/xml application/xhtml+xml application/xml-dtd 6 | AddOutputFilterByType DEFLATE application/rdf+xml application/rss+xml application/atom+xml image/svg+xml 7 | AddOutputFilterByType DEFLATE text/css text/javascript application/javascript application/x-javascript 8 | AddOutputFilterByType DEFLATE font/opentype application/font-otf application/x-font-otf 9 | AddOutputFilterByType DEFLATE font/truetype application/font-ttf application/x-font-ttf 10 | 11 | 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Comet Cache Pro [![Build Status](https://travis-ci.org/websharks/comet-cache-pro.svg?branch=000000-dev)](https://travis-ci.org/websharks/comet-cache-pro) 2 | 3 | Caching plugin for WordPress®. 4 | 5 | Comet Cache™ Pro is a commercial plugin available at [http://cometcache.com](http://cometcache.com). The plugin is hosted here on a public Github repository in order to better faciliate community contributions from developers and users alike. If you have a suggestion, a bug report, or a patch for an issue, feel free to submit it here. We do ask, however, that if you are using the plugin on a live site that you please purchase a valid license from the [website](http://cometcache.com). We cannot provide support to anyone that does not hold a valid license key. 6 | -------------------------------------------------------------------------------- /src/includes/traits/Plugin/CdnUtils.php: -------------------------------------------------------------------------------- 1 | options['enable']) { 18 | return; // Nothing to do. 19 | } 20 | if (!$this->options['cdn_enable']) { 21 | return; // Nothing to do. 22 | } 23 | $this->updateOptions(['cdn_invalidation_counter' => ++$this->options['cdn_invalidation_counter']]); 24 | } 25 | } 26 | /*[/pro]*/ 27 | -------------------------------------------------------------------------------- /src/includes/traits/Shared/EscapeUtils.php: -------------------------------------------------------------------------------- 1 | `1`. 16 | * 17 | * @return string Escaped string; e.g. `Raam\'s the lead developer`. 18 | */ 19 | public function escSq($string, $times = 1) 20 | { 21 | return str_replace("'", str_repeat('\\', abs($times))."'", (string) $string); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/includes/templates/htaccess/canonical-urls-no-ts-enable.txt: -------------------------------------------------------------------------------- 1 | # Force NO trailing slash on all virtual requests (except WP admin area). 2 | 3 | RewriteEngine On 4 | RewriteBase %%REWRITE_BASE%% 5 | 6 | # If not a real file or directory. 7 | RewriteCond %{REQUEST_FILENAME} !-f 8 | RewriteCond %{REQUEST_FILENAME} !-d 9 | 10 | # Not a part of the WP admin area. 11 | RewriteCond %{REQUEST_URI} !(?:^|/)wp\-admin(?:/|$) 12 | 13 | # Not a REST request, which never redirects. 14 | RewriteCond %{REQUEST_URI} !(?:^|/)%%REST_REQUEST_PREFIX_AS_REGEX_FRAG%%(?:/|$) 15 | 16 | # If there is a trailing slash. 17 | RewriteCond %{REQUEST_URI} /$ 18 | 19 | # Force NO trailing slash on all virtual requests. 20 | RewriteRule ^(.*)/$ $1 [QSA,L,R=301] 21 | 22 | -------------------------------------------------------------------------------- /src/includes/templates/htaccess/canonical-urls-ts-enable.txt: -------------------------------------------------------------------------------- 1 | # Force a trailing slash on all virtual requests (except WP admin area). 2 | 3 | RewriteEngine On 4 | RewriteBase %%REWRITE_BASE%% 5 | 6 | # If not a real file or directory. 7 | RewriteCond %{REQUEST_FILENAME} !-f 8 | RewriteCond %{REQUEST_FILENAME} !-d 9 | 10 | # Not a part of the WP admin area. 11 | RewriteCond %{REQUEST_URI} !(?:^|/)wp\-admin(?:/|$) 12 | 13 | # Not a REST request, which never redirects. 14 | RewriteCond %{REQUEST_URI} !(?:^|/)%%REST_REQUEST_PREFIX_AS_REGEX_FRAG%%(?:/|$) 15 | 16 | # If there is no trailing slash. 17 | RewriteCond %{REQUEST_URI} !/$ 18 | 19 | # Force a trailing slash on all virtual requests. 20 | RewriteRule ^(.*)$ $1/ [QSA,L,R=301] 21 | 22 | -------------------------------------------------------------------------------- /src/includes/classes/MenuPage.php: -------------------------------------------------------------------------------- 1 | comment markers here please. 19 | -------------------------------------------------------------------------------- /src/includes/traits/Plugin/ActionUtils.php: -------------------------------------------------------------------------------- 1 | autoCache(); 26 | exit(); 27 | } 28 | /*[/pro]*/ 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/includes/traits/Ac/ShutdownUtils.php: -------------------------------------------------------------------------------- 1 | &$_value) { 26 | if (is_array($_value)) { 27 | $_value = $this->ksortDeep($_value, $flags); 28 | } 29 | } // unset($_key, $_value); // Housekeeping. 30 | 31 | return $array; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/includes/traits/Plugin/WcpJetpackUtils.php: -------------------------------------------------------------------------------- 1 | cacheKey('autoClearCacheOnJetpackCustomCss', $args))) { 22 | return $counter; // Already did this. 23 | } 24 | $done = true; // Flag as having been done. 25 | 26 | if (empty($args['is_preview']) && class_exists('\\Jetpack')) { 27 | $counter += $this->autoClearCache(); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # ---------------------------------------------------------------------------------------------------------------------- 2 | 3 | # Container. 4 | 5 | dist: trusty 6 | sudo: required 7 | language: generic 8 | script: ./.travis.bash 9 | 10 | # ---------------------------------------------------------------------------------------------------------------------- 11 | 12 | # Notifications. 13 | 14 | notifications: 15 | email: false # Disable. 16 | slack: websharks:EpVKoMF6MQKjLKVw0CAX33Og 17 | 18 | # ---------------------------------------------------------------------------------------------------------------------- 19 | 20 | # Begin custom matrix. 21 | 22 | matrix: # Tests for Comet Cache WordPress plugin. 23 | 24 | include: # Cover both ends of our PHP spectrum. 25 | 26 | - env: CI_RUN=PHP_VERSION=7.0,WP=standard,WP_VERSION=latest 27 | - env: CI_RUN=PHP_VERSION=7.0,WP=multisite,WP_VERSION=latest 28 | 29 | fast_finish: true # Before allowed failures. 30 | 31 | # 32 | -------------------------------------------------------------------------------- /src/includes/templates/ac-plugin.txt: -------------------------------------------------------------------------------- 1 | addFilter('comet_cache_version_salt', 'my_ac_version_salt_shaker'); 15 | } 16 | function my_ac_version_salt_shaker($version_salt) 17 | { 18 | if (mb_stripos($_SERVER['HTTP_USER_AGENT'], 'iphone') !== false) { 19 | $version_salt .= 'iphones'; // Give iPhones their own variation of the cache. 20 | } elseif (mb_stripos($_SERVER['HTTP_USER_AGENT'], 'android') !== false) { 21 | $version_salt .= 'androids'; // Androic variation. 22 | } else { 23 | $version_salt .= 'other'; // A default group. 24 | } 25 | return $version_salt; 26 | } 27 | my_ac_plugin(); // Run this plugin. 28 | -------------------------------------------------------------------------------- /src/includes/functions/i18n-utils.php: -------------------------------------------------------------------------------- 1 | options['enable']) { 18 | return; // Nothing to do. 19 | } 20 | /*[pro strip-from="lite"]*/ 21 | if ($this->options['cache_max_age_disable_if_load_average_is_gte'] && ($load_averages = $this->sysLoadAverages())) { 22 | if (max($load_averages) >= $this->options['cache_max_age_disable_if_load_average_is_gte']) { 23 | return; // Don't expire the cache when load average is high. 24 | } 25 | } 26 | /*[/pro]*/ 27 | 28 | /*[pro strip-from="lite"]*/ 29 | if ($this->options['stats_enable']) { 30 | $dir_stats = Classes\DirStats::instance(); 31 | $dir_stats->forCache(true); 32 | } 33 | /*[/pro]*/ 34 | $this->wurgeCache(); // Purge now. 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/includes/traits/Plugin/WcpPluginUtils.php: -------------------------------------------------------------------------------- 1 | applyWpFilters(GLOBAL_NS.'_auto_clear_on_plugin_activation_deactivation', true)) { 26 | return 0; // Nothing to do here. 27 | } 28 | 29 | add_action('shutdown', [$this, 'wipeOpcacheByForce'], PHP_INT_MAX); 30 | 31 | return $this->{($network_wide ? 'autoWipeCache' : 'autoClearCache')}(); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/includes/traits/Plugin/.build.php: -------------------------------------------------------------------------------- 1 | cacheKey('postStatuses'))) { 18 | return $statuses; // Already did this. 19 | } 20 | $statuses = get_post_stati(); 21 | $statuses = array_keys($statuses); 22 | 23 | return $statuses; 24 | } 25 | 26 | /** 27 | * All built-in post statuses. 28 | * 29 | * @since 150821 Improving bbPress support. 30 | * 31 | * @return array All built-in post statuses. 32 | */ 33 | public function builtInPostStatuses() 34 | { 35 | if (!is_null($statuses = &$this->cacheKey('builtInPostStatuses'))) { 36 | return $statuses; // Already did this. 37 | } 38 | $statuses = []; // Initialize. 39 | 40 | foreach (get_post_stati([], 'objects') as $_key => $_status) { 41 | if (!empty($_status->_builtin)) { 42 | $statuses[] = $_status->name; 43 | } 44 | } 45 | unset($_key, $_status); // Housekeeping. 46 | 47 | return $statuses; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/includes/traits/Shared/TrimUtils.php: -------------------------------------------------------------------------------- 1 | &$_values) { 25 | $_values = $this->trimDeep($_values, $chars, $extra_chars); 26 | } 27 | unset($_key, $_values); // Housekeeping. 28 | 29 | return $values; 30 | } 31 | $string = (string) $values; 32 | $chars = (string) $chars; 33 | $extra_chars = (string) $extra_chars; 34 | 35 | $chars = isset($chars[0]) ? $chars : " \r\n\t\0\x0B"; 36 | $chars = $chars.$extra_chars; // Concatenate. 37 | 38 | return trim($string, $chars); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/includes/functions/wp-cache-postload.php: -------------------------------------------------------------------------------- 1 | is_running) { 17 | return; // Not applicable. 18 | } 19 | $advanced_cache->doWpAction('before_'.$GLOBAL_NS.'_'.__FUNCTION__, get_defined_vars()); 20 | 21 | /*[pro strip-from="lite"]*/ 22 | if (!empty($advanced_cache->postload['invalidate_when_logged_in'])) { 23 | $advanced_cache->maybeInvalidateWhenLoggedInPostload(); 24 | } 25 | if (!empty($advanced_cache->postload['when_logged_in'])) { 26 | $advanced_cache->maybeStartObWhenLoggedInPostload(); 27 | } /*[/pro]*/ 28 | if (!empty($advanced_cache->postload['filter_status_header'])) { 29 | $advanced_cache->maybeFilterStatusHeaderPostload(); 30 | } 31 | if (!empty($advanced_cache->postload['set_debug_info'])) { 32 | $advanced_cache->maybeSetDebugInfoPostload(); 33 | } 34 | if (!empty($advanced_cache->postload['wp_main_query'])) { 35 | add_action('wp', [$advanced_cache, 'wpMainQueryPostload'], PHP_INT_MAX); 36 | } 37 | $advanced_cache->doWpAction('after_'.$GLOBAL_NS.'_'.__FUNCTION__, get_defined_vars()); 38 | $advanced_cache->doWpAction($GLOBAL_NS.'_'.__FUNCTION__.'_complete', get_defined_vars()); 39 | } 40 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore --------------------------------------------------------------------------------------------------------------- 2 | 3 | # Local 4 | 5 | .~* 6 | ._* 7 | 8 | # Logs 9 | 10 | *.log 11 | 12 | # Backups 13 | 14 | *~ 15 | *.bak 16 | 17 | # Vagrant 18 | 19 | .vagrant/ 20 | 21 | # TypeScript 22 | 23 | typings/ 24 | 25 | # IntelliJ 26 | 27 | .idea/ 28 | 29 | # Sublime 30 | 31 | *.sublime-project 32 | *.sublime-workspace 33 | 34 | # Vendor 35 | 36 | vendor/ 37 | 38 | # NodeJS 39 | 40 | node_modules/ 41 | 42 | # Bower 43 | 44 | bower_components/ 45 | 46 | # SASS 47 | 48 | .sass-cache/ 49 | 50 | # Elastic Beanstalk 51 | 52 | .elasticbeanstalk/ 53 | 54 | # CTAGs 55 | 56 | *.ctags 57 | *.tags 58 | 59 | # VCS 60 | 61 | .git/ 62 | 63 | .svn/ 64 | _svn/ 65 | 66 | CVS/ 67 | .cvsignore 68 | 69 | .bzr/ 70 | .bzrignore 71 | 72 | .hg/ 73 | .hgignore 74 | 75 | SCCS/ 76 | RCS/ 77 | 78 | # PC Files 79 | 80 | $RECYCLE.BIN/ 81 | Desktop.ini 82 | Thumbs.db 83 | ehthumbs.db 84 | 85 | # Mac Files 86 | 87 | .AppleDB 88 | .AppleDouble 89 | .AppleDesktop 90 | .com.apple.timemachine.donotpresent 91 | Network Trash Folder 92 | Temporary Items 93 | .LSOverride 94 | .Spotlight-V100 95 | .VolumeIcon.icns 96 | .TemporaryItems 97 | .fseventsd 98 | .DS_Store 99 | .Trashes 100 | .apdisk 101 | Icon? 102 | !Icons 103 | ._* 104 | 105 | # ---------------------------------------------------------------------------------------------------------------------- 106 | 107 | # 108 | # Put your rules in custom comment markers. 109 | # 110 | -------------------------------------------------------------------------------- /src/includes/traits/Plugin/StatsUtils.php: -------------------------------------------------------------------------------- 1 | applyWpFilters(GLOBAL_NS.'_statsLogPinger_enable', IS_PRO)) { 22 | return; // Stats collection disabled by site. 23 | } elseif ($this->options['last_pro_stats_log'] >= strtotime('-1 week')) { 24 | return; // No reason to keep pinging. 25 | } 26 | $this->updateOptions(['last_pro_stats_log' => time()]); 27 | 28 | $stats_api_endpoint = 'https://stats.wpsharks.io/log'; 29 | $stats_api_url_args = [ // See: 30 | 'os' => PHP_OS, 31 | 'php_version' => PHP_VERSION, 32 | 'wp_version' => get_bloginfo('version'), 33 | 'mysql_version' => $this->wpdb()->db_version(), 34 | 'product_version' => VERSION, // Plugin version. 35 | 'product' => SLUG_TD.(IS_PRO ? '-pro' : ''), 36 | ]; 37 | $stats_api_url = add_query_arg(urlencode_deep($stats_api_url_args), $stats_api_endpoint); 38 | wp_remote_get($stats_api_url, ['blocking' => false, 'sslverify' => false]); 39 | } 40 | } 41 | /*[/pro]*/ 42 | -------------------------------------------------------------------------------- /src/includes/traits/Plugin/UrlUtils.php: -------------------------------------------------------------------------------- 1 | options['cache_clear_s2clean_enable']) { 25 | return $counter; // Not enabled at this time. 26 | } 27 | if (!$this->functionIsPossible('s2clean')) { 28 | return $counter; // Not possible. 29 | } 30 | $counter += s2clean()->md_cache_clear(); 31 | 32 | return $counter; 33 | } 34 | 35 | /** 36 | * Clear (i.e., reset) s2Clean cache. 37 | * 38 | * @since 151002 While adding OPCache support. 39 | * 40 | * @param bool $manually True if clearing is done manually. 41 | * @param bool $maybe Defaults to a true value. 42 | * 43 | * @return int Total files cleared in s2Clean. 44 | */ 45 | public function clearS2CleanCache($manually = false, $maybe = true) 46 | { 47 | if (!is_multisite() || is_main_site() || current_user_can($this->network_cap)) { 48 | return $this->wipeS2CleanCache($manually, $maybe); 49 | } 50 | return 0; // Not applicable. 51 | } 52 | } 53 | /*[/pro]*/ 54 | -------------------------------------------------------------------------------- /src/includes/traits/Plugin/WcpEvalUtils.php: -------------------------------------------------------------------------------- 1 | options['cache_clear_eval_code']) { 25 | return $result; // Not enabled at this time. 26 | } 27 | if (!$this->options['cache_clear_eval_code']) { 28 | return $result; // Nothing to eval. 29 | } 30 | if (!$this->functionIsPossible('eval')) { 31 | return $result; // Not possible. 32 | } 33 | ob_start(); // Buffer output from PHP code. 34 | eval('?>'.$this->options['cache_clear_eval_code'].'wipeEvalCode($manually, $maybe); 52 | } 53 | } 54 | /*[/pro]*/ 55 | -------------------------------------------------------------------------------- /src/includes/traits/Shared/PatternUtils.php: -------------------------------------------------------------------------------- 1 | setCache(new WurflCache([WurflCache::DIR => $cache_dir])); 25 | $BrowscapUpdater->update(BrowscapIniLoader::PHP_INI_LITE); 26 | } 27 | $Browscap = new Browscap(); 28 | $Browscap->setCache(new WurflCache([WurflCache::DIR => $cache_dir])); 29 | $BrowscapLiteParser = new BrowscapLiteParser($Browscap); 30 | $UserAgent = $BrowscapLiteParser->parse($UA_to_test); 31 | 32 | echo 'os.name = '.$UserAgent->getOperatingSystem()->getName()."\n\n"; 33 | 34 | echo 'device.type = '.$UserAgent->getDevice()->getType()."\n"; 35 | echo 'device.is_mobile = '.$UserAgent->getDevice()->getIsMobile()."\n\n"; 36 | 37 | echo 'browser.name = '.$UserAgent->getBrowser()->getName()."\n"; 38 | echo 'browser.version.major = '.$UserAgent->getBrowser()->getVersion()->getMajor()."\n"; 39 | echo 'browser.version = '.trim($UserAgent->getBrowser()->getVersion()->getMajor().'.'.$UserAgent->getBrowser()->getVersion()->getMinor())."\n"; 40 | -------------------------------------------------------------------------------- /src/includes/traits/Plugin/WcpWooCommerceUtils.php: -------------------------------------------------------------------------------- 1 | cacheKey('autoClearPostCacheOnWooCommerceSetStock'))) { 22 | return $counter; // Already did this. 23 | } 24 | $done = true; // Flag as having been done. 25 | 26 | if (class_exists('\\WooCommerce')) { 27 | $counter += $this->autoClearPostCache($product->get_id()); 28 | } 29 | } 30 | 31 | /** 32 | * Automatically clears cache file for a WooCommerce Product when its stock status is changed. 33 | * 34 | * @since 161119 Improving WooCommerce Compatibility. 35 | * 36 | * @attaches-to `woocommerce_product_set_stock_status` hook. 37 | * 38 | * @param string|int $product_id A WooCommerce product ID. 39 | */ 40 | public function autoClearPostCacheOnWooCommerceSetStockStatus($product_id) 41 | { 42 | $counter = 0; // Initialize. 43 | 44 | if (!is_null($done = &$this->cacheKey('autoClearPostCacheOnWooCommerceSetStockStatus'))) { 45 | return $counter; // Already did this. 46 | } 47 | $done = true; // Flag as having been done. 48 | 49 | if (class_exists('\\WooCommerce')) { 50 | $counter += $this->autoClearPostCache($product_id); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/includes/traits/Ac/ClientSideUtils.php: -------------------------------------------------------------------------------- 1 | sendNoCacheHeaders(); // Disallow. 25 | } // Else, allow client-side caching because `ABC` is a true-ish value. 26 | } elseif (COMET_CACHE_EXCLUDE_CLIENT_SIDE_URIS && (empty($_SERVER['REQUEST_URI']) || preg_match(COMET_CACHE_EXCLUDE_CLIENT_SIDE_URIS, $_SERVER['REQUEST_URI']))) { 27 | return $this->sendNoCacheHeaders(); // Disallow. 28 | } 29 | return; // Allow client-side caching; default behavior in this mode. 30 | 31 | case false: // Global config disallows; check inclusions. 32 | 33 | if (isset($_GET[$short_name_lc.'ABC'])) { 34 | if (filter_var($_GET[$short_name_lc.'ABC'], FILTER_VALIDATE_BOOLEAN)) { 35 | return; // Allow, because `ABC` is a false-ish value. 36 | } // Else, disallow client-side caching because `ABC` is a true-ish value. 37 | } 38 | return $this->sendNoCacheHeaders(); // Disallow; default behavior in this mode. 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/includes/traits/Plugin/WcpSettingUtils.php: -------------------------------------------------------------------------------- 1 | cacheKey('autoClearCacheOnSettingChanges', [$pagenow, $other_option_page, $settings_updated]))) { 24 | return $counter; // Already did this. 25 | } 26 | $done = true; // Flag as having been done. 27 | 28 | if ($pagenow === 'options-general.php' && $other_option_page) { 29 | return $counter; // Nothing to do. See: https://git.io/viYqE 30 | } 31 | 32 | if ($pagenow === 'options-general.php' && $settings_updated) { 33 | $this->addWpHtaccess(); // Update .htaccess if applicable 34 | $counter += $this->autoClearCache(); 35 | } elseif ($pagenow === 'options-reading.php' && $settings_updated) { 36 | $counter += $this->autoClearCache(); 37 | } elseif ($pagenow === 'options-discussion.php' && $settings_updated) { 38 | $counter += $this->autoClearCache(); 39 | } elseif ($pagenow === 'options-permalink.php' && $settings_updated) { 40 | $this->addWpHtaccess(); // Update .htaccess if applicable 41 | $counter += $this->autoClearCache(); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/includes/classes/MenuPage/Options/Directory.php: -------------------------------------------------------------------------------- 1 | '."\n"; 23 | 24 | echo ' '."\n"; 25 | echo ' '.__('Cache Directory', SLUG_TD)."\n"; 26 | echo ' '."\n"; 27 | 28 | echo '
'."\n"; 29 | echo '

'.__('Base Cache Directory (Must be Writable; i.e., Permissions 755 or Higher)', SLUG_TD).'

'."\n"; 30 | echo '

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

'."\n"; 31 | echo '
'.esc_html(WP_CONTENT_DIR).'//
'."\n"; 32 | echo '
'."\n"; 33 | 34 | echo ''."\n"; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/includes/traits/Plugin/WcpCdnUtils.php: -------------------------------------------------------------------------------- 1 | options['cdn_enable']) { 26 | return -(integer) $this->options['cdn_invalidation_counter']; 27 | } 28 | if ($maybe && !$this->options['cache_clear_cdn_enable']) { 29 | return -(integer) $this->options['cdn_invalidation_counter']; 30 | } 31 | $this->updateOptions(['cdn_invalidation_counter' => ++$this->options['cdn_invalidation_counter']]); 32 | 33 | return (integer) $this->options['cdn_invalidation_counter']; 34 | } 35 | 36 | /** 37 | * Clears the CDN cache. 38 | * 39 | * @since 151002 Implementing CDN cache clearing. 40 | * 41 | * @param bool $manually True if clearing is done manually. 42 | * @param bool $maybe Defaults to a true value. 43 | * 44 | * @throws \Exception If a clear failure occurs. 45 | * 46 | * @return int CDN invalidation counter after clearing. 47 | * Zero, or a negative integer if clearing did not take place. 48 | */ 49 | public function clearCdnCache($manually = false, $maybe = true) 50 | { 51 | return $this->wipeCdnCache($manually, $maybe); 52 | } 53 | } 54 | /*[/pro]*/ 55 | -------------------------------------------------------------------------------- /.build.props: -------------------------------------------------------------------------------- 1 | project_title = Comet Cache Pro 2 | 3 | project_owner = websharks 4 | project_slug = comet-cache-pro 5 | project_issues_slug = comet-cache 6 | 7 | project_namespace = WebSharks\\CometCache\\Pro 8 | project_sub_namespace = CometCachePro 9 | 10 | project_text_domain = comet-cache 11 | project_slack_channel = comet-cache 12 | 13 | project_version = %y%m%d 14 | 15 | project_php_required_version = 5.4 16 | project_php_tested_up_to_version = ${php.version} 17 | 18 | project_wp_required_version = 4.2 19 | project_wp_tested_up_to_version = 4.9-alpha 20 | 21 | project_other_zip_tgz_fileset_exclusions = README.md, **/composer.lock, **/composer.json, **/src/vendor/bin/, **/src/vendor/browscap/browscap-php/bin/, **/src/vendor/symfony/console/Resources/bin/ 22 | 23 | project_lite_title = Comet Cache 24 | project_lite_slug = comet-cache 25 | 26 | project_lite_namespace = WebSharks\\CometCache 27 | project_lite_sub_namespace = CometCache 28 | 29 | project_lite_text_domain = comet-cache 30 | project_lite_text_domain_regex_replacement_pattern = \$this\-\>text_domain|SLUG_TD 31 | 32 | project_lite_alter_namespace_in_other_files_pattern = src/includes/templates/advanced-cache.txt 33 | project_lite_other_zip_tgz_fileset_exclusions = README.md, **/cdn-filters.txt, **/options-pro.png, **/pro-updater.png, **/stats.png, **/stats-f*.png, **/comet-cache-pro.pot, **/composer.lock, **/composer.json 34 | -------------------------------------------------------------------------------- /src/includes/traits/Plugin/BbPressUtils.php: -------------------------------------------------------------------------------- 1 | isBbPressActive()) { 30 | return []; 31 | } 32 | if (!is_null($types = &$this->cacheKey('bbPressPostTypes'))) { 33 | return $types; // Already did this. 34 | } 35 | $types = []; // Initialize. 36 | $types[] = bbp_get_forum_post_type(); 37 | $types[] = bbp_get_topic_post_type(); 38 | $types[] = bbp_get_reply_post_type(); 39 | 40 | return $types; 41 | } 42 | 43 | /** 44 | * bbPress post statuses. 45 | * 46 | * @since 150821 Improving bbPress support. 47 | * 48 | * @return array All bbPress post statuses. 49 | */ 50 | public function bbPressStatuses() 51 | { 52 | if (!$this->isBbPressActive()) { 53 | return []; 54 | } 55 | if (!is_null($statuses = &$this->cacheKey('bbPressStatuses'))) { 56 | return $statuses; // Already did this. 57 | } 58 | $statuses = []; // Initialize. 59 | 60 | foreach (get_post_stati([], 'objects') as $_key => $_status) { 61 | if (isset($_status->label_count['domain']) && $_status->label_count['domain'] === 'bbpress') { 62 | $statuses[] = $_status->name; 63 | } 64 | } 65 | unset($_key, $_status); // Housekeeping. 66 | 67 | return $statuses; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/includes/traits/Shared/BlogUtils.php: -------------------------------------------------------------------------------- 1 | siteid`. 16 | */ 17 | public function getBlogs() 18 | { 19 | if (!is_multisite()) { 20 | return []; // Not possible. 21 | } 22 | $sites = []; // Initialize. 23 | 24 | foreach (get_sites([ 25 | 'number' => 100, 'count' => false, 26 | 'network_id' => $GLOBALS['wpdb']->siteid, 27 | ]) as $_site) { 28 | if (($_site = get_site($_site))) { 29 | $sites[] = $_site->to_array(); 30 | } // For compatibiliey with old `wp_get_sites()`. 31 | } // unset($_site); 32 | 33 | return $sites; 34 | } 35 | 36 | /** 37 | * Get blog details. 38 | * 39 | * @since 150821 Improving multisite compat. 40 | * 41 | * @param int $blog_id For which blog ID? 42 | * 43 | * @return \stdClass|null Blog details if possible. 44 | * 45 | * @note The return value of this function is NOT cached in support of `switch_to_blog()`. 46 | */ 47 | public function blogDetails($blog_id = 0) 48 | { 49 | if (!is_multisite() || $this->isAdvancedCache()) { 50 | return null; // Not possible. 51 | } 52 | if (($blog_id = (int) $blog_id) < 0) { 53 | $blog_id = (int) get_current_site()->blog_id; 54 | } 55 | if (!$blog_id) { 56 | $blog_id = (int) get_current_blog_id(); 57 | } 58 | if (!$blog_id || $blog_id < 0) { 59 | return null; // Not possible. 60 | } 61 | $details = get_blog_details($blog_id); 62 | 63 | return is_object($details) ? $details : null; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/includes/traits/Plugin/WcpSitemapUtils.php: -------------------------------------------------------------------------------- 1 | cacheKey('autoClearXmlSitemapsCache'))) { 25 | return $counter; // Already did this. 26 | } 27 | $done = true; // Flag as having been done. 28 | 29 | if (!$this->options['enable']) { 30 | return $counter; // Nothing to do. 31 | } 32 | if (!$this->options['cache_clear_xml_sitemaps_enable']) { 33 | return $counter; // Nothing to do. 34 | } 35 | if (!$this->options['cache_clear_xml_sitemap_patterns']) { 36 | return $counter; // Nothing to do. 37 | } 38 | if (!is_dir($cache_dir = $this->cacheDir())) { 39 | return $counter; // Nothing to do. 40 | } 41 | if (!($regex_frags = $this->buildHostCachePathRegexFragsFromWcUris($this->options['cache_clear_xml_sitemap_patterns'], ''))) { 42 | return $counter; // There are no patterns to look for. 43 | } 44 | $regex = $this->buildHostCachePathRegex('', '\/'.$regex_frags.'\.'); 45 | $counter += $this->clearFilesFromHostCacheDir($regex); 46 | 47 | if ($counter && is_admin() && (!IS_PRO || $this->options['change_notifications_enable'])) { 48 | $this->enqueueNotice(sprintf(__('Found %1$s in the cache for XML sitemaps; auto-clearing.', SLUG_TD), esc_html($this->i18nFiles($counter))), ['combinable' => true]); 49 | } 50 | return $counter; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/includes/traits/Plugin/WcpUrlUtils.php: -------------------------------------------------------------------------------- 1 | cacheKey('autoClearUrlsCache'))) { 27 | return $counter; // Already did this. 28 | } 29 | $done = true; // Flag as having been done. 30 | 31 | if (!$this->options['enable']) { 32 | return $counter; // Nothing to do. 33 | } 34 | if (!$this->options['cache_clear_urls']) { 35 | return $counter; // Nothing to do. 36 | } 37 | if (!is_dir($cache_dir = $this->cacheDir())) { 38 | return $counter; // Nothing to do. 39 | } 40 | foreach (preg_split('/['."\r\n".']+/', $this->options['cache_clear_urls'], -1, PREG_SPLIT_NO_EMPTY) as $_url) { 41 | if (mb_stripos($_url, 'http') === 0) { 42 | $_regex = $this->buildCachePathRegexFromWcUrl($_url); 43 | $counter += $this->deleteFilesFromCacheDir($_regex); 44 | } 45 | } 46 | unset($_url, $_regex); // Housekeeping. 47 | 48 | if ($counter && is_admin() && (!IS_PRO || $this->options['change_notifications_enable'])) { 49 | $this->enqueueNotice(sprintf(__('Found %1$s in the cache matching a custom list of URLs; auto-clearing.', SLUG_TD), esc_html($this->i18nFiles($counter))), ['combinable' => true]); 50 | } 51 | return $counter; 52 | } 53 | } 54 | /*[/pro]*/ 55 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "library", 3 | "license": "GPL-3.0+", 4 | "name": "websharks/comet-cache-pro", 5 | 6 | "homepage": "https://github.com/websharks/comet-cache-pro", 7 | "support": { 8 | "source": "https://github.com/websharks/comet-cache-pro", 9 | "issues": "https://github.com/websharks/comet-cache/issues" 10 | }, 11 | 12 | "description": "A popular caching plugin for WordPress.", 13 | "keywords": [ 14 | "websharks", 15 | "comet cache", 16 | "wordpress", 17 | "caching", 18 | "cache" 19 | ], 20 | 21 | "authors": [{ 22 | "name": "websharks", 23 | "homepage": "http://websharks.org", 24 | "role": "company" 25 | }, { 26 | "name": "jaswrks", 27 | "homepage": "http://jaswrks.com", 28 | "role": "developer" 29 | }, { 30 | "name": "raamdev", 31 | "homepage": "https://raamdev.com", 32 | "role": "developer" 33 | }], 34 | 35 | "require": { 36 | "php": ">=5.4", 37 | "websharks/sharkicons": "160221", 38 | "websharks/wp-php-rv": "160824.6416", 39 | "websharks/html-compressor": "170420.24924", 40 | "thadafinser/user-agent-parser": "1.5.0", 41 | "browscap/browscap-php": "3.0.0", 42 | "ramsey/uuid": "3.*" 43 | }, 44 | "require-lite": { 45 | "php": ">=5.4", 46 | "websharks/sharkicons": "160221", 47 | "websharks/wp-php-rv": "160824.6416" 48 | }, 49 | "require-dev": { 50 | "package/bourbon": "4.2.3", 51 | "websharks/wp-i18n-tools": "dev-master" 52 | }, 53 | 54 | "autoload": { 55 | "psr-4": { 56 | "WebSharks\\CometCache\\Pro\\Classes\\": "src/includes/classes/", 57 | "WebSharks\\CometCache\\Pro\\Traits\\": "src/includes/traits/", 58 | "WebSharks\\CometCache\\Pro\\Interfaces\\": "src/includes/interfaces/" 59 | } 60 | }, 61 | "config": { 62 | "vendor-dir": "src/vendor", 63 | "preferred-install": "dist" 64 | }, 65 | "minimum-stability": "dev", 66 | "prefer-stable": true, 67 | 68 | "repositories": [{ 69 | "type": "package", 70 | "package": { 71 | "name": "package/bourbon", 72 | "version": "4.2.3", 73 | "dist": { 74 | "url": "https://github.com/thoughtbot/bourbon/releases/download/v4.2.3/bourbon-v4.2.3.zip", 75 | "type": "zip" 76 | } 77 | } 78 | }] 79 | } 80 | -------------------------------------------------------------------------------- /src/client-s/css/menu-pages/_colors.scss: -------------------------------------------------------------------------------- 1 | $anchor-color: #033A63; 2 | $anchor-hover-active-color: #467629; 3 | 4 | $pre-code-color: #eee; 5 | $pre-code-bg-color: #222; 6 | $pre-code-box-shadow-color: #000; 7 | $code-bg-color: rgba(178, 178, 178, 0.25); 8 | 9 | $hr-bg-color-a: rgba(0, 0, 0, 0); 10 | $hr-bg-color-b: rgba(0, 0, 0, 0.75); 11 | $hr-bg-color-c: rgba(0, 0, 0, 0); 12 | 13 | $img-screenshot-border-color: #afafaf; 14 | $img-screenshot-box-shadow-color: rgba(0, 0, 0, 0.2); 15 | $img-screenshot-bg-color: #fff; 16 | 17 | $primary-switch-color: #000; 18 | $primary-switch-bg-color: #f1e982; 19 | $primary-switch-border-color: rgba(0, 0, 0, 0.07); 20 | $primary-switch-box-shadow-color-a: rgba(0, 0, 0, 0.25); 21 | $primary-switch-box-shadow-color-b: #fff; 22 | 23 | $input-color: #333; 24 | $input-bg-color: #e8e8e8; 25 | $input-border-color: #848484; 26 | $input-box-shadow-color: rgba(132, 132, 132, 0.5); 27 | 28 | $input-focus-color: #000; 29 | $input-focus-bg-color: #e2e2e2; 30 | $input-focus-box-shadow-color-a: #fff; 31 | $input-focus-box-shadow-color-b: rgba(132, 132, 132, 0.25); 32 | 33 | $input-placeholder-color: rgba(0, 0, 0, 0.2); 34 | 35 | $button-color: #fff; 36 | $button-bg-color: #033A63; 37 | $button-hover-bg-color: #467629; 38 | $button-submit-bg-color: #467629; 39 | $button-submit-hover-bg-color: #033A63; 40 | $button-border-color: rgba(0, 0, 0, 0.5); 41 | $button-box-shadow-color-a: rgba(0, 0, 0, 0.25); 42 | $button-box-shadow-color-b: rgba(0, 0, 0, 0.2); 43 | $button-box-shadow-color-c: rgba(255, 255, 255, 0.1); 44 | 45 | $info-bg-color: #cadfed; 46 | $info-border-color: #216095; 47 | 48 | $notice-bg-color: #fffde8; 49 | $notice-border-color: #e6db55; 50 | 51 | $warning-bg-color: #ffefd3; 52 | $warning-border-color: #e6db55; 53 | 54 | $error-bg-color: #ffc0cb; 55 | $error-border-color: #711e1e; 56 | 57 | $heading-panel-togglers-bg-color: #033A63; 58 | 59 | $panel-heading-color: #eee; 60 | $panel-heading-hover-color: #fff; 61 | $panel-heading-bg-color: #033A63; 62 | $panel-heading-bg-color-fade: #20669A; 63 | $panel-heading-box-shadow-color: rgba(0, 0, 0, 0.25); 64 | 65 | $panel-body-color: #222; 66 | $panel-body-p-color: #666; 67 | $panel-body-p-notice-color: #000; 68 | $panel-body-bg-color: #fff; 69 | $panel-body-border-color: #848484; 70 | $panel-body-box-shadow-color-a: rgba(0, 0, 0, 0.25); 71 | $panel-body-box-shadow-color-b: rgba(0, 0, 0, 0.25); 72 | -------------------------------------------------------------------------------- /src/includes/traits/Shared/ReplaceUtils.php: -------------------------------------------------------------------------------- 1 | strReplaceOnce($needle, $replace, $haystack, true); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/includes/classes/MenuPage/Options/Safeguards.php: -------------------------------------------------------------------------------- 1 | '."\n"; 23 | 24 | echo ' '."\n"; 25 | echo ' '.__('Plugin Deletion Safeguards', SLUG_TD)."\n"; 26 | echo ' '."\n"; 27 | 28 | echo '
'."\n"; 29 | echo ' '."\n"; 30 | echo '

'.__('Uninstall on Plugin Deletion; or Safeguard Options?', SLUG_TD).'

'."\n"; 31 | echo '

'.sprintf(__('Tip: By default, if you delete %1$s using the plugins menu in WordPress, nothing is lost. However, if you want to completely uninstall %1$s you should set this to Yes and THEN deactivate & delete %1$s from the plugins menu in WordPress. This way %1$s will erase your options for the plugin, erase directories/files created by the plugin, remove the advanced-cache.php file, terminate CRON jobs, etc. It erases itself from existence completely.', SLUG_TD), esc_html(NAME)).'

'."\n"; 32 | echo '

'."\n"; 36 | echo '
'."\n"; 37 | 38 | echo ''."\n"; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/client-s/images/inline-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/includes/classes/AbsBaseAp.php: -------------------------------------------------------------------------------- 1 | {$property} = $value; 61 | } 62 | 63 | /** 64 | * Closure overloading. 65 | * 66 | * @since 150422 Rewrite. 67 | */ 68 | public function __call($closure, $args) 69 | { 70 | $closure = (string) $closure; 71 | 72 | if (isset($this->{$closure}) && is_callable($this->{$closure})) { 73 | return call_user_func_array($this->{$closure}, $args); 74 | } 75 | throw new \Exception(sprintf(__('Undefined method/closure: `%1$s`.', SLUG_TD), $closure)); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/client-s/css/admin-bar/_animations.scss: -------------------------------------------------------------------------------- 1 | 2 | 3 | // Animation :: spin. 4 | 5 | @mixin comet_cache-admin-bar-animation-spin { 6 | @include animation-duration(0.75s); 7 | @include animation-fill-mode(both); 8 | @include animation-timing-function(linear); 9 | @include animation-iteration-count(infinite); 10 | @include animation-name(comet_cache-admin-bar-animation-spin); 11 | } 12 | 13 | .comet_cache-admin-bar-animation-spin { 14 | @include comet_cache-admin-bar-animation-spin; 15 | } 16 | 17 | @include keyframes(comet_cache-admin-bar-animation-spin) { 18 | 0% { 19 | @include transform(rotate(0deg)); 20 | } 21 | 22 | 100% { 23 | @include transform(rotate(360deg)); 24 | } 25 | } 26 | 27 | // Animation :: zoom-in-down. 28 | 29 | @mixin comet_cache-admin-bar-animation-zoom-in-down { 30 | @include animation-duration(0.75s); 31 | @include animation-fill-mode(both); 32 | @include animation-name(comet_cache-admin-bar-animation-zoom-in-down); 33 | } 34 | 35 | .comet_cache-admin-bar-animation-zoom-in-down { 36 | @include comet_cache-admin-bar-animation-zoom-in-down; 37 | } 38 | 39 | @include keyframes(comet_cache-admin-bar-animation-zoom-in-down) { 40 | from { 41 | @include transform(scale3d(0.1, 0.1, 0.1) translate3d(0, -1000px, 0)); 42 | @include animation-timing-function(cubic-bezier(0.55, 0.055, 0.675, 0.19)); 43 | 44 | opacity: 0; 45 | } 46 | 47 | 60% { 48 | @include transform(scale3d(0.475, 0.475, 0.475) translate3d(0, 60px, 0)); 49 | @include animation-timing-function(cubic-bezier(0.175, 0.885, 0.32, 1)); 50 | 51 | opacity: 1; 52 | } 53 | } 54 | 55 | // Animation :: zoom-out-up. 56 | 57 | @mixin comet_cache-admin-bar-animation-zoom-out-up { 58 | @include animation-duration(0.15s); 59 | @include animation-fill-mode(both); 60 | @include animation-name(comet_cache-admin-bar-animation-zoom-out-up); 61 | } 62 | 63 | .comet_cache-admin-bar-animation-zoom-out-up { 64 | @include comet_cache-admin-bar-animation-zoom-out-up; 65 | } 66 | 67 | @include keyframes(comet_cache-admin-bar-animation-zoom-out-up) { 68 | 40% { 69 | @include transform(scale3d(0.475, 0.475, 0.475) translate3d(0, 60px, 0)); 70 | @include animation-timing-function(cubic-bezier(0.55, 0.055, 0.675, 0.19)); 71 | 72 | opacity: 1; 73 | } 74 | 75 | 100% { 76 | @include transform-origin(center bottom); 77 | @include transform(scale3d(0.1, 0.1, 0.1) translate3d(0, -2000px, 0)); 78 | @include animation-timing-function(cubic-bezier(0.175, 0.885, 0.32, 1)); 79 | 80 | opacity: 0; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/client-s/css/admin-bar/_ajax-response.scss: -------------------------------------------------------------------------------- 1 | 2 | 3 | $ajax-response-text-color: #fff; 4 | $ajax-response-bg-color: #15181b; 5 | $ajax-response-bg-hover-color: #000; 6 | $ajax-response-box-shadow-color: #23282d; 7 | $ajax-response-code-color: #000; 8 | $ajax-response-code-bg-color: #eee; 9 | 10 | .comet_cache-ajax-response { 11 | @include user-select(none); 12 | @include sharkicon(times-circle, after); 13 | 14 | display: none; 15 | left: 50%; 16 | top: 100px; 17 | z-index: 10000; 18 | position: fixed; 19 | width: 700px; 20 | height: auto; 21 | min-height: 64px; 22 | padding: 15px; 23 | text-align: center; 24 | outline: none; 25 | cursor: pointer; 26 | border-radius: 5px; 27 | box-sizing: border-box; 28 | margin: 0 0 0 -350px; 29 | background: $ajax-response-bg-color; 30 | color: $ajax-response-text-color; 31 | box-shadow: 0 0 5px 0 $ajax-response-box-shadow-color; 32 | 33 | &:hover, 34 | &.-hovered { 35 | background-color: $ajax-response-bg-hover-color; 36 | } 37 | 38 | &.-wipe, 39 | &.-clear { 40 | &::before { 41 | left: 0; 42 | top: 0; 43 | width: 64px; 44 | height: 64px; 45 | position: absolute; 46 | } 47 | } 48 | 49 | &.-wipe { 50 | &::before { 51 | content: url('../images/wipe-response.png'); 52 | } 53 | } 54 | 55 | &.-clear { 56 | &::before { 57 | content: url('../images/clear-response.png'); 58 | } 59 | } 60 | 61 | &::after { 62 | top: 5px; 63 | right: 8px; 64 | opacity: 0.5; 65 | font-size: 120%; 66 | position: absolute; 67 | } 68 | 69 | p { 70 | margin: 0; 71 | padding: 0; 72 | opacity: 0.35; 73 | font: 15px/1.2em sans-serif; 74 | } 75 | 76 | p:first-child { 77 | opacity: 1; 78 | } 79 | 80 | code { 81 | border-radius: 3px; 82 | padding: 1px 3px; 83 | color: $ajax-response-code-color; 84 | background: $ajax-response-code-bg-color; 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/includes/classes/MenuPage/Options/FeedRequests.php: -------------------------------------------------------------------------------- 1 | '."\n"; 23 | 24 | echo ' '."\n"; 25 | echo ' '.__('Feed Caching', SLUG_TD)."\n"; 26 | echo ' '."\n"; 27 | 28 | echo '
'."\n"; 29 | echo ' '."\n"; 30 | echo '

'.__('Caching Enabled for RSS, RDF, Atom Feeds?', SLUG_TD).'

'."\n"; 31 | echo '

'.__('This should almost ALWAYS be set to No. UNLESS, you\'re sure that you want to cache your feeds. If you use a web feed management provider like Google® Feedburner and you set this option to Yes, you may experience delays in the detection of new posts. NOTE: If you do enable this, it is highly recommended that you also enable automatic Feed Clearing too. Please see the section above: "Automatic Cache Clearing". Find the sub-section titled: "Auto-Clear RSS/RDF/ATOM Feeds".', SLUG_TD).'

'."\n"; 32 | echo '

'."\n"; 36 | echo '

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

'."\n"; 37 | echo '
'."\n"; 38 | 39 | echo ''."\n"; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/includes/classes/MenuPage/Options/ImportExport.php: -------------------------------------------------------------------------------- 1 | plugin->isProPreview()) { 23 | echo '
'."\n"; 24 | 25 | echo ' '."\n"; 26 | echo ' '.__('Import/Export Options', SLUG_TD)."\n"; 27 | echo ' '."\n"; 28 | 29 | echo '
'."\n"; 30 | echo ' '."\n"; 31 | echo '

'.sprintf(__('Import Options from Another %1$s Installation?', SLUG_TD), esc_html(NAME)).'

'."\n"; 32 | echo '

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

'."\n"; 33 | echo '

'."\n"; 34 | echo '
'."\n"; 35 | echo '

'.sprintf(__('Export Existing Options from this %1$s Installation?', SLUG_TD), esc_html(NAME)).'

'."\n"; 36 | echo ' '."\n"; 39 | echo '

'.sprintf(__('Download your existing options and import them all into another %1$s installation; saves time on future installs.', SLUG_TD), esc_html(NAME)).'

'."\n"; 40 | echo '
'."\n"; 41 | 42 | echo '
'."\n"; 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/includes/traits/Shared/ServerUtils.php: -------------------------------------------------------------------------------- 1 | staticKey(__FUNCTION__))) { 18 | return $is; // Already cached this. 19 | } 20 | if (!empty($_SERVER['SERVER_SOFTWARE']) && is_string($_SERVER['SERVER_SOFTWARE'])) { 21 | if (mb_stripos($_SERVER['SERVER_SOFTWARE'], 'apache') !== false) { 22 | return $is = true; 23 | } elseif (mb_stripos($_SERVER['SERVER_SOFTWARE'], 'litespeed') !== false) { 24 | return $is = true; 25 | } 26 | } // Checking `SERVER_SOFTWARE` is faster. 27 | 28 | if ($this->functionIsPossible('apache_get_version')) { 29 | return $is = true; 30 | } 31 | return $is = false; 32 | } 33 | 34 | /** 35 | * Is running on Nginx? 36 | * 37 | * @since 151002 This is Nginx? 38 | * 39 | * @return bool True if running Nginx. 40 | */ 41 | public function isNginx() 42 | { 43 | if (!is_null($is = &$this->staticKey(__FUNCTION__))) { 44 | return $is; // Already cached this. 45 | } 46 | if (!empty($_SERVER['SERVER_SOFTWARE']) && is_string($_SERVER['SERVER_SOFTWARE'])) { 47 | if (mb_stripos($_SERVER['SERVER_SOFTWARE'], 'nginx') !== false) { 48 | return $is = true; 49 | } 50 | } // Checking `SERVER_SOFTWARE` is faster. 51 | 52 | if (!empty($_SERVER['WP_NGINX_CONFIG'])) { 53 | return $is = true; // See: 54 | } 55 | return $is = false; 56 | } 57 | 58 | /** 59 | * Is running on Windows IIS? 60 | * 61 | * @since 151002 This is Windows IIS? 62 | * 63 | * @return bool True if running Windows IIS. 64 | */ 65 | public function isIis() 66 | { 67 | if (!is_null($is = &$this->staticKey(__FUNCTION__))) { 68 | return $is; // Already cached this. 69 | } 70 | if (!empty($_SERVER['SERVER_SOFTWARE']) && is_string($_SERVER['SERVER_SOFTWARE'])) { 71 | if (mb_stripos($_SERVER['SERVER_SOFTWARE'], 'microsoft-iis') !== false) { 72 | return $is = true; 73 | } elseif (mb_stripos($_SERVER['SERVER_SOFTWARE'], 'expressiondevserver') !== false) { 74 | return $is = true; 75 | } 76 | } // Checking `SERVER_SOFTWARE` is faster. 77 | 78 | return $is = false; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/includes/classes/MenuPage/Options/HostExclusions.php: -------------------------------------------------------------------------------- 1 | plugin->canConsiderDomainMapping()); 24 | 25 | if ($this->plugin->applyWpFilters(GLOBAL_NS.'_exclude_hosts_option_enable', $exclude_hosts_option_enable)) { 26 | echo '
'."\n"; 27 | 28 | echo ' '."\n"; 29 | echo ' '.__('Host Exclusions', SLUG_TD)."\n"; 30 | echo ' '."\n"; 31 | 32 | echo '
'."\n"; 33 | echo '

'.__('Don\'t Cache These Special Host Exclusion Patterns?', SLUG_TD).'

'."\n"; 34 | echo '

'.__('If there are specific domains that should not be cached, you can enter them here so they are excluded automatically. The easiest way to exclude a host is to enter the full domain name on a line of it\'s own in the field below, e.g., site1.example.com.', SLUG_TD).'

'."\n"; 35 | echo '

'.__('This field also supports Watered-Down Regex syntax, which means that you can also exclude a pattern like: *.example.com or *.example.*. So for instance, if you wanted to exclude all child sites and only cache pages on the Main Site of a Network installation, you could exclude all sub-domains using: *.mynetwork.com. That excludes all sub-domains, but not mynetwork.com by itself.', SLUG_TD).'

'."\n"; 36 | 37 | echo '

'."\n"; 38 | 39 | echo '

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

'."\n"; 40 | 41 | echo '
'."\n"; 42 | echo '
'."\n"; 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/includes/classes/MenuPage/Options/Developers.php: -------------------------------------------------------------------------------- 1 | '."\n"; 23 | 24 | echo ' '."\n"; 25 | echo ' '.__('Theme/Plugin Developers', SLUG_TD)."\n"; 26 | echo ' '."\n"; 27 | 28 | echo '
'."\n"; 29 | echo ' '."\n"; 30 | echo '

'.__('Developing a Theme or Plugin for WordPress?', SLUG_TD).'

'."\n"; 31 | echo '

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

'."\n"; 32 | echo '
'."\n"; 33 | echo '

'.sprintf(__('Writing "Advanced Cache" Plugins Specifically for %1$s', SLUG_TD), esc_html(NAME)).'

'."\n"; 34 | echo '

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

'."\n"; 35 | echo '

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

'."\n"; 36 | echo '
'."\n"; 37 | 38 | echo ''."\n"; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/includes/traits/Plugin/WcpOpcacheUtils.php: -------------------------------------------------------------------------------- 1 | options['cache_clear_opcache_enable']) { 24 | return $counter; // Not enabled at this time. 25 | } 26 | if (!$this->functionIsPossible('opcache_reset')) { 27 | return $counter; // Not possible. 28 | } 29 | if (!($status = $this->sysOpcacheStatus())) { 30 | return $counter; // Not possible. 31 | } 32 | if (empty($status->opcache_enabled)) { 33 | return $counter; // Not necessary. 34 | } 35 | if (empty($status->opcache_statistics->num_cached_keys)) { 36 | return $counter; // Not possible. 37 | } 38 | if ($files) { // Specific files? 39 | foreach ($files as $_file) { 40 | $counter += (int) opcache_invalidate($_file, true); 41 | } // unset($_file); // Housekeeping. 42 | } elseif (opcache_reset()) { // True if a reset occurs. 43 | $counter += $status->opcache_statistics->num_cached_keys; 44 | } 45 | return $counter; 46 | } 47 | 48 | /** 49 | * Clear (i.e., reset) OPCache. 50 | * 51 | * @since 151002 Adding OPCache support. 52 | * 53 | * @param bool $manually True if clearing is done manually. 54 | * @param bool $maybe Defaults to a true value. 55 | * 56 | * @return int Total keys cleared. 57 | */ 58 | public function clearOpcache($manually = false, $maybe = true) 59 | { 60 | if (!is_multisite() || is_main_site() || current_user_can($this->network_cap)) { 61 | return $this->wipeOpcache($manually, $maybe); 62 | } 63 | return 0; // Not applicable. 64 | } 65 | 66 | /** 67 | * Wipe the Opcache (by force). 68 | * 69 | * @since 160521 Improving OPCache support. 70 | * 71 | * @return int Total keys cleared. 72 | */ 73 | public function wipeOpcacheByForce() 74 | { 75 | return $this->wipeOpcache(false, false); 76 | } 77 | 78 | /** 79 | * Clear AC class file from Opcache (by force). 80 | * 81 | * @since 151215 Adding OPCache support. 82 | * 83 | * @return int Total keys cleared. 84 | */ 85 | public function clearAcDropinFromOpcacheByForce() 86 | { 87 | return $this->wipeOpcache(false, false, [WP_CONTENT_DIR.'/advanced-cache.php']); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/includes/classes/MenuPage/Options/UserAgentExclusions.php: -------------------------------------------------------------------------------- 1 | '."\n"; 23 | 24 | echo ' '."\n"; 25 | echo ' '.__('User-Agent Exclusions', SLUG_TD)."\n"; 26 | echo ' '."\n"; 27 | 28 | echo '
'."\n"; 29 | echo '

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

'."\n"; 30 | echo '

'.__('Sometimes there are special cases when a particular user-agent (e.g., a specific browser or a specific type of device); should be shown a page on your site that is NOT from the cache (and that resulting page should never be cached). This is where you will enter those if you need to (one per line). Searches are performed against the HTTP_USER_AGENT (caSe insensitive). A wildcard * character can also be used when necessary; e.g., Android *; Chrome/* Mobile (where * = 0 or more characters that are NOT a slash /). Other special characters include: ** = 0 or more characters of any kind, including / slashes; ^ = beginning of the string; $ = end of the string. To learn more about this syntax, please see this KB article.', SLUG_TD).'

'."\n"; 31 | echo '

'."\n"; 32 | echo '

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

'."\n"; 33 | echo '

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

'."\n"; 34 | echo '
'."\n"; 35 | 36 | echo ''."\n"; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/includes/classes/MenuPage/Options/RefererExclusions.php: -------------------------------------------------------------------------------- 1 | '."\n"; 23 | 24 | echo ' '."\n"; 25 | echo ' '.__('HTTP Referrer Exclusions', SLUG_TD)."\n"; 26 | echo ' '."\n"; 27 | 28 | echo '
'."\n"; 29 | echo '

'.__('Don\'t Cache These Special HTTP Referrer Exclusion Patterns?', SLUG_TD).'

'."\n"; 30 | echo '

'.__('Sometimes there are special cases where a particular referring URL (or referring domain) that sends you traffic; or even a particular group of referring URLs or domains that send you traffic; should result in a page being loaded on your site that is NOT from the cache (and that resulting page should never be cached). This is where you will enter those if you need to (one per line). Searches are performed against the HTTP_REFERER (caSe insensitive). A wildcard * character can also be used when necessary; e.g., *.domain.com (where * = 0 or more characters that are NOT a slash /). Other special characters include: ** = 0 or more characters of any kind, including / slashes; ^ = beginning of the string; $ = end of the string. To learn more about this syntax, please see this KB article.', SLUG_TD).'

'."\n"; 31 | echo '

'."\n"; 32 | echo '

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

'."\n"; 33 | echo '

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

'."\n"; 34 | echo '
'."\n"; 35 | 36 | echo ''."\n"; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/includes/stub.php: -------------------------------------------------------------------------------- 1 | cacheKey('autoClearCustomPostTypeArchiveCache', $post_id))) { 30 | return $counter; // Already did this. 31 | } 32 | $done = true; // Flag as having been done. 33 | 34 | if (!$this->options['enable']) { 35 | return $counter; // Nothing to do. 36 | } 37 | if (!$this->options['cache_clear_custom_post_type_enable']) { 38 | return $counter; // Nothing to do. 39 | } 40 | if (!is_dir($cache_dir = $this->cacheDir())) { 41 | return $counter; // Nothing to do. 42 | } 43 | if (!($post_type = get_post_type($post_id))) { 44 | return $counter; // Nothing to do. 45 | } 46 | if (!($all_custom_post_types = get_post_types(['_builtin' => false]))) { 47 | return $counter; // No custom post types. 48 | } 49 | if (!in_array($post_type, array_keys($all_custom_post_types), true)) { 50 | return $counter; // This is NOT a custom post type. 51 | } 52 | if (!($custom_post_type = get_post_type_object($post_type))) { 53 | return $counter; // Unable to retrieve post type. 54 | } 55 | if (empty($custom_post_type->labels->name) || !($custom_post_type_name = $custom_post_type->labels->name)) { 56 | $custom_post_type_name = __('Untitled', SLUG_TD); 57 | } 58 | if (!($custom_post_type_archive_link = get_post_type_archive_link($post_type))) { 59 | return $counter; // Nothing to do; no link to work from in this case. 60 | } 61 | $regex = $this->buildHostCachePathRegex($custom_post_type_archive_link); 62 | $counter += $this->clearFilesFromHostCacheDir($regex); 63 | 64 | if ($counter && is_admin() && (!IS_PRO || $this->options['change_notifications_enable'])) { 65 | $this->enqueueNotice(sprintf(__('Found %1$s in the cache for Custom Post Type: %2$s; auto-clearing.', SLUG_TD), esc_html($this->i18nFiles($counter)), esc_html($custom_post_type_name)), ['combinable' => true]); 66 | } 67 | $counter += $this->autoClearXmlFeedsCache('custom-post-type', $post_id); 68 | 69 | return $counter; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/includes/classes/AdvancedCache.php: -------------------------------------------------------------------------------- 1 | is_running = true; 80 | $this->timer = microtime(true); 81 | 82 | $this->loadAcPlugins(); 83 | $this->registerShutdownFlag(); 84 | $this->maybeIgnoreUserAbort(); 85 | $this->maybeStopBrowserCaching(); 86 | /*[pro strip-from="lite"]*/ 87 | $this->maybePostloadInvalidateWhenLoggedIn(); 88 | /*[/pro]*/ 89 | $this->maybeStartOutputBuffering(); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/includes/classes/MenuPage/Options/UriExclusions.php: -------------------------------------------------------------------------------- 1 | '."\n"; 23 | 24 | echo ' '."\n"; 25 | echo ' '.__('URI Exclusions', SLUG_TD)."\n"; 26 | echo ' '."\n"; 27 | 28 | echo '
'."\n"; 29 | echo '

'.__('Don\'t Cache These Special URI Exclusion Patterns?', SLUG_TD).'

'."\n"; 30 | echo '

'.__('Sometimes there are certain cases where a particular file, or a particular group of files, should never be cached. This is where you will enter those if you need to (one per line). Searches are performed against the REQUEST_URI; i.e., /path/?query (caSe insensitive). So, don\'t put in full URLs here, just word fragments found in the file path (or query string) is all you need, excluding the http:// and domain name. A wildcard * character can also be used when necessary; e.g., /category/abc-followed-by-* (where * = 0 or more characters that are NOT a slash /). Other special characters include: ** = 0 or more characters of any kind, including / slashes; ^ = beginning of the string; $ = end of the string. To learn more about this syntax, please see this KB article.', SLUG_TD).'

'."\n"; 31 | echo '

'."\n"; 32 | 33 | echo '

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

'."\n"; 34 | echo '

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

'."\n"; 35 | if (is_multisite() && defined('SUBDOMAIN_INSTALL') && !SUBDOMAIN_INSTALL) { 36 | echo '

'.__('Multisite Network w/ Sub-Directories: You can also use URI Exclusion Patterns to exclude specific sites from being cached, e.g., /site1/*.', SLUG_TD).'

'."\n"; 37 | } 38 | echo '
'."\n"; 39 | 40 | echo ''."\n"; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/includes/classes/Notes.php: -------------------------------------------------------------------------------- 1 | notes = []; 32 | } 33 | 34 | /** 35 | * Get notes. 36 | * 37 | * @since 161119 Notes. 38 | * 39 | * @return array Notes. 40 | */ 41 | public function notes() 42 | { 43 | return $this->notes; 44 | } 45 | 46 | /** 47 | * Add note. 48 | * 49 | * @param string $key Key. 50 | * @param string $note Note. 51 | * 52 | * @since 161119 Notes. 53 | */ 54 | public function add($key, $note) 55 | { 56 | $this->notes[$key] = $note; 57 | } 58 | 59 | /** 60 | * Add line break. 61 | * 62 | * @since 161119 Notes. 63 | */ 64 | public function addLineBreak() 65 | { 66 | $this->notes[] = "\n"; 67 | } 68 | 69 | /** 70 | * Add divider. 71 | * 72 | * @since 161119 Notes. 73 | */ 74 | public function addDivider() 75 | { 76 | $this->notes[] = str_repeat('.', 70); 77 | } 78 | 79 | /** 80 | * Add ASCII artwork. 81 | * 82 | * @param string $note Note. 83 | * 84 | * @since 161119 Notes. 85 | */ 86 | public function addAsciiArt($note) 87 | { 88 | $this->notes[] = '*´¨) 89 | ¸.•´¸.•*´¨) ¸.•*¨) 90 | (¸.•´ (¸.•` ¤ '.$note.' ¤ ´¨)'; 91 | } 92 | 93 | /** 94 | * As HTML comments. 95 | * 96 | * @since 161119 HTML comments. 97 | */ 98 | public function asHtmlComments() 99 | { 100 | $html_comments = ''; // Initialize. 101 | $longest_key_size = 0; // Initialize. 102 | 103 | foreach ($this->notes as $_key => $_note) { 104 | if (is_string($_key) && $_key && isset($_note[0])) { 105 | $longest_key_size = max($longest_key_size, mb_strlen($_key.':')); 106 | } 107 | } // unset($_key, $_note); // Housekeeping. 108 | 109 | foreach ($this->notes as $_key => $_note) { 110 | if (is_integer($_key)) { 111 | if ($_note === "\n") { 112 | $html_comments .= "\n"; 113 | } elseif (isset($_note[0])) { 114 | $html_comments .= ''."\n"; 115 | } 116 | } elseif ($_key && !isset($_note[0])) { 117 | $html_comments .= ''."\n"; 118 | } elseif (!$_key && isset($_note[0])) { 119 | $html_comments .= ''."\n"; 120 | } elseif ($_key && isset($_note[0])) { 121 | $html_comments .= ''."\n"; 122 | } 123 | } // unset($_key, $_note); // Housekeeping. 124 | 125 | return trim($html_comments); 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /src/includes/classes/MenuPage/Options/Nf404Requests.php: -------------------------------------------------------------------------------- 1 | '."\n"; 23 | 24 | echo ' '."\n"; 25 | echo ' '.__('404 Requests', SLUG_TD)."\n"; 26 | echo ' '."\n"; 27 | 28 | echo '
'."\n"; 29 | echo ' '."\n"; 30 | echo '

'.__('Caching Enabled for 404 Requests?', SLUG_TD).'

'."\n"; 31 | echo '

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

'."\n"; 32 | echo '

'."\n"; 36 | echo '

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

'."\n"; 37 | echo '

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

'."\n"; 38 | echo '
'."\n"; 39 | 40 | echo ''."\n"; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/includes/traits/Shared/SysUtils.php: -------------------------------------------------------------------------------- 1 | cacheKey('sysLoadAverages'))) { 18 | return $averages; // Already cached these. 19 | } 20 | if (!$this->functionIsPossible('sys_getloadavg')) { 21 | return $averages = []; 22 | } 23 | if (!is_array($averages = sys_getloadavg()) || !$averages) { 24 | return $averages = []; 25 | } 26 | $averages = array_map('floatval', $averages); 27 | $averages = array_slice($averages, 0, 3); 28 | // i.e., 1m, 5m, 15m; see: 29 | 30 | return $averages; 31 | } 32 | 33 | /** 34 | * System memory info. 35 | * 36 | * @since 151002 Adding cache directory statistics. 37 | * 38 | * @return \stdClass|bool System memory info. 39 | */ 40 | public function sysMemoryStatus() 41 | { 42 | if (!is_null($status = &$this->cacheKey('sysMemoryStatus'))) { 43 | return $status; // Already cached this. 44 | } 45 | if (!$this->functionIsPossible('shell_exec')) { 46 | return $status = false; 47 | } 48 | if (!($free = trim((string) @shell_exec('free')))) { 49 | return $status = false; 50 | } 51 | if (!($free_lines = explode("\n", $free))) { 52 | return $status = false; 53 | } 54 | if (empty($free_lines[1])) { 55 | return $status = false; 56 | } 57 | if (!($memory = explode(' ', $free_lines[1]))) { 58 | return $status = false; 59 | } 60 | if (!($memory = array_merge(array_filter($memory)))) { 61 | return $status = false; 62 | } 63 | if (!isset($memory[1], $memory[2])) { 64 | return $status = false; 65 | } 66 | if (($total = (integer) $memory[1]) <= 0) { 67 | return $status = false; 68 | } 69 | $used = (integer) $memory[2]; 70 | $percent = $used / $total * 100; 71 | $percentage = sprintf(__('%s%%', SLUG_TD), number_format($percent, 2, '.', '')); 72 | $status = (object) compact('total', 'used', 'percent', 'percentage'); 73 | 74 | return $status; 75 | } 76 | 77 | /** 78 | * System opcache status/details. 79 | * 80 | * @since 151002 Adding cache directory statistics. 81 | * 82 | * @return \stdClass|bool System opcache status/details. 83 | */ 84 | public function sysOpcacheStatus() 85 | { 86 | if (!is_null($status = &$this->cacheKey('sysOpcacheStatus'))) { 87 | return $status; // Already cached this. 88 | } 89 | if (!$this->functionIsPossible('opcache_get_status')) { 90 | return $status = false; 91 | } 92 | if (!is_array($status = opcache_get_status(false)) || !$status) { 93 | return $status = false; 94 | } 95 | if (empty($status['opcache_enabled'])) { 96 | return $status = false; 97 | } 98 | return json_decode(json_encode($status)); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/client-s/css/menu-pages/_heading.scss: -------------------------------------------------------------------------------- 1 | .plugin-menu-page-heading { 2 | .plugin-menu-page-stats-button { 3 | float: right; 4 | 5 | @media (max-width: 1199px) { 6 | float: none; 7 | display: block; 8 | margin: auto; 9 | } 10 | } 11 | 12 | .plugin-menu-page-restore-defaults { 13 | float: right; 14 | margin: 0 1em 0 0; 15 | 16 | @media (max-width: 1199px) { 17 | float: none; 18 | clear: left; 19 | text-align: center; 20 | margin: 0 auto; 21 | } 22 | } 23 | 24 | .plugin-menu-page-panel-togglers { 25 | float: right; 26 | margin: 0 1em 0 0; 27 | 28 | @media (max-width: 1199px) { 29 | display: none; 30 | } 31 | 32 | button { 33 | background: $heading-panel-togglers-bg-color !important; 34 | } 35 | } 36 | 37 | .plugin-menu-page-upsells { 38 | float: right; 39 | clear: right; 40 | text-align: right; 41 | max-width: 350px; 42 | margin: 1em 0 0; 43 | 44 | @media (max-width: 1199px) { 45 | float: none; 46 | clear: both; 47 | text-align: center; 48 | margin: 0 auto 0 auto; 49 | padding: 1em 0 0 0; 50 | } 51 | 52 | a { 53 | text-decoration: none; 54 | line-height: 1.5em; 55 | margin: 0 0.5em; 56 | display: inline-block; 57 | } 58 | } 59 | 60 | .plugin-menu-page-support-links { 61 | float: right; 62 | clear: right; 63 | text-align: right; 64 | max-width: 400px; 65 | margin: .5em 0 0; 66 | 67 | @media (max-width: 1199px) { 68 | float: none; 69 | clear: both; 70 | text-align: center; 71 | margin: 1em auto 1em auto; 72 | } 73 | 74 | a { 75 | text-decoration: none; 76 | margin: 0 0.5em; 77 | display: inline-block; 78 | } 79 | } 80 | 81 | .plugin-menu-page-mailing-list-links { 82 | float: right; 83 | clear: right; 84 | text-align: right; 85 | max-width: 400px; 86 | margin: .5em 0 0; 87 | 88 | @media (max-width: 1199px) { 89 | float: none; 90 | clear: both; 91 | text-align: center; 92 | margin: 1em auto 1em auto; 93 | } 94 | 95 | a { 96 | text-decoration: none; 97 | margin: 0 0.5em; 98 | display: inline-block; 99 | } 100 | } 101 | 102 | .plugin-menu-page-version { 103 | float: right; 104 | clear: right; 105 | min-width: 350px; 106 | margin: 0.5em 0 0 0; 107 | text-align: right; 108 | 109 | @media (max-width: 1199px) { 110 | float: none; 111 | clear: both; 112 | text-align: center; 113 | } 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /src/includes/traits/Shared/CacheLockUtils.php: -------------------------------------------------------------------------------- 1 | applyWpFilters(GLOBAL_NS.'\\share::disable_cache_locking', false) 25 | || $this->applyWpFilters(GLOBAL_NS.'_disable_cache_locking', false) 26 | ) { 27 | return false; // Disabled cache locking. 28 | } 29 | if (!($wp_config_file = $this->findWpConfigFile())) { 30 | throw new \Exception(__('Unable to find the wp-config.php file.', SLUG_TD)); 31 | } 32 | $lock_type = 'flock'; // Default lock type. 33 | $lock_type = $this->applyWpFilters(GLOBAL_NS.'\\share::cache_lock_lock_type', $lock_type); 34 | $lock_type = $this->applyWpFilters(GLOBAL_NS.'_cache_lock_type', $lock_type); 35 | 36 | if (!in_array($lock_type, ['flock', 'sem'], true)) { 37 | $lock_type = 'flock'; // Default lock type. 38 | } 39 | if ($lock_type === 'sem' && $this->functionIsPossible('sem_get')) { 40 | if (($ipc_key = ftok($wp_config_file, 'w'))) { 41 | if (($resource = sem_get($ipc_key, 1)) && sem_acquire($resource)) { 42 | return ['type' => 'sem', 'resource' => $resource]; 43 | } 44 | } 45 | } 46 | if (!($tmp_dir = $this->getTmpDir())) { 47 | throw new \Exception(__('No writable tmp directory.', SLUG_TD)); 48 | } 49 | $inode_key = fileinode($wp_config_file); 50 | $mutex = $tmp_dir.'/'.SLUG_TD.'-'.$inode_key.'.lock'; 51 | 52 | if (!($resource = fopen($mutex, 'wb')) || !flock($resource, LOCK_EX)) { 53 | throw new \Exception(__('Unable to obtain an exclusive lock.', SLUG_TD)); 54 | } 55 | 56 | @chmod($mutex, 0666); // See https://git.io/v2WAt 57 | 58 | return ['type' => 'flock', 'resource' => $resource]; 59 | } 60 | 61 | /** 62 | * Release an exclusive lock on the cache directory. 63 | * 64 | * @since 150422 Rewrite. Updated 151002 to remove the `array` typecast. 65 | * 66 | * @param array|mixed $lock Type & resource. 67 | */ 68 | public function cacheUnlock($lock) 69 | { 70 | if (!is_array($lock)) { 71 | return; // Not possible. 72 | // Or, they disabled cache locking. 73 | } 74 | if (empty($lock['type']) || empty($lock['resource'])) { 75 | return; // Not possible. 76 | } 77 | if (!is_resource($lock['resource'])) { 78 | return; // Not possible. 79 | } 80 | if ($lock['type'] === 'sem') { 81 | sem_release($lock['resource']); 82 | } elseif ($lock['type'] === 'flock') { 83 | flock($lock['resource'], LOCK_UN); 84 | fclose($lock['resource']); 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/includes/interfaces/Shared/CachePathConsts.php: -------------------------------------------------------------------------------- 1 | &$_GET, 22 | '_REQUEST' => &$_REQUEST, 23 | ]; 24 | $key_suffixes = ['AC', 'ABC']; 25 | $lc_short_name = mb_strtolower(SHORT_NAME); 26 | 27 | foreach ($super_globals as $_key => &$_array) { 28 | foreach ($key_suffixes as $_suffix) { 29 | if (!array_key_exists('zc'.$_suffix, $_array)) { 30 | continue; // No relevant key in array. 31 | } 32 | if ($_key === '_GET' && !isset($_GET[$lc_short_name.$_suffix])) { 33 | $_GET[$lc_short_name.$_suffix] = $_array['zc'.$_suffix]; 34 | } // This sets the new key with the value from the old key. 35 | 36 | foreach ($super_globals as $__key => &$__array) { 37 | unset($__array['zc'.$_suffix]); // Purge old key. 38 | } // Must unset temporary vars by reference. 39 | unset($__key, $__array); // Housekeeping. 40 | // 41 | } // unset($_suffix); // Housekeeping. 42 | } // Must unset temporary vars by reference. 43 | unset($_key, $_array); 44 | } 45 | 46 | /** 47 | * Back compat. with `ZENCACHE_` constants. 48 | * 49 | * @since 150422 Rewrite. 50 | * @since 17xxxx Polishing a little. 51 | * @since 17xxxx Making this more dynamic. 52 | */ 53 | public static function zenCacheConstants() 54 | { 55 | $uc_global_ns = mb_strtoupper(GLOBAL_NS); 56 | 57 | if (!($constants = get_defined_constants(true)) || empty($constants['user'])) { 58 | return; // Nothing to do; i.e. no user-defined constants. 59 | } 60 | foreach ($constants['user'] as $_constant => $_value) { 61 | if (mb_stripos($_constant, 'ZENCACHE_') !== 0) { 62 | continue; // Nothing to do here. 63 | } elseif (!($_constant_sub_name = mb_substr($_constant, 9))) { 64 | continue; // Nothing to do here. 65 | } 66 | if (!defined($uc_global_ns.'_'.$_constant_sub_name)) { 67 | define($uc_global_ns.'_'.$_constant_sub_name, $_value); 68 | } // Sets new const with the value from the old const. 69 | } // unset($_constant, $_value); // Just a little housekeeping. 70 | 71 | if (isset($_SERVER['ZENCACHE_ALLOWED']) && !isset($_SERVER[$uc_global_ns.'_ALLOWED'])) { 72 | $_SERVER[$uc_global_ns.'_ALLOWED'] = $_SERVER['ZENCACHE_ALLOWED']; 73 | } // Sets new super-global with the value from the old super-global key. 74 | } 75 | 76 | /** 77 | * Back compat. with constants. 78 | * 79 | * @since 160706 Renaming `*_ALLOW_BROWSER_CACHE` to `*_ALLOW_CLIENT_SIDE_CACHE`. 80 | * @since 17xxxx Polishing things up a little. 81 | * @since 17xxxx Making this more dynamic. 82 | */ 83 | public static function browserCacheConstant() 84 | { 85 | $uc_global_ns = mb_strtoupper(GLOBAL_NS); 86 | 87 | if (defined($uc_global_ns.'_ALLOW_BROWSER_CACHE')) { 88 | define($uc_global_ns.'_ALLOW_CLIENT_SIDE_CACHE', constant($uc_global_ns.'_ALLOW_BROWSER_CACHE')); 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/includes/classes/MenuPageOptions.php: -------------------------------------------------------------------------------- 1 | GLOBAL_NS, '_wpnonce' => wp_create_nonce()]), self_admin_url('/admin.php'))).'">'."\n"; 23 | 24 | new MenuPage\Options\Heading(); 25 | 26 | /* ----------------------------------------------------------------------------------------- */ 27 | 28 | echo '
'."\n"; 29 | 30 | /* ----------------------------------------------------------------------------------------- */ 31 | 32 | echo '

'. 33 | ' '.__('Basic Configuration (Required)', SLUG_TD). 34 | ' '.sprintf(__('Review these basic options and %1$s™ will be ready-to-go!', SLUG_TD), esc_html(NAME)).''. 35 | '

'; 36 | 37 | new MenuPage\Options\Enable(); 38 | new MenuPage\Options\ProUpdater(); 39 | new MenuPage\Options\Safeguards(); 40 | 41 | /* ----------------------------------------------------------------------------------------- */ 42 | 43 | echo '

'. 44 | ' '.__('Advanced Configuration (All Optional)', SLUG_TD). 45 | ' '.__('Recommended for advanced site owners only; already pre-configured for most WP installs.', SLUG_TD).''. 46 | '

'; 47 | 48 | new MenuPage\Options\ManualClearing(); 49 | new MenuPage\Options\AutomaticClearing(); 50 | 51 | new MenuPage\Options\Statistics(); 52 | new MenuPage\Options\Directory(); 53 | new MenuPage\Options\Memcached(); 54 | new MenuPage\Options\Expiration(); 55 | 56 | new MenuPage\Options\ClientSide(); 57 | new MenuPage\Options\UserRequests(); 58 | new MenuPage\Options\GetRequests(); 59 | new MenuPage\Options\Nf404Requests(); 60 | new MenuPage\Options\FeedRequests(); 61 | 62 | new MenuPage\Options\HostExclusions(); 63 | new MenuPage\Options\UriExclusions(); 64 | new MenuPage\Options\RefererExclusions(); 65 | new MenuPage\Options\UserAgentExclusions(); 66 | 67 | new MenuPage\Options\AutoCacheEngine(); 68 | new MenuPage\Options\HtmlCompressor(); 69 | new MenuPage\Options\StaticCdnFilters(); 70 | new MenuPage\Options\ApacheOptimizations(); 71 | 72 | new MenuPage\Options\MobileMode(); 73 | new MenuPage\Options\VersionSalt(); 74 | 75 | new MenuPage\Options\Developers(); 76 | new MenuPage\Options\ImportExport(); 77 | 78 | /* ----------------------------------------------------------------------------------------- */ 79 | 80 | echo '
'."\n"; 81 | echo ' '."\n"; 82 | echo '
'."\n"; 83 | 84 | /* ----------------------------------------------------------------------------------------- */ 85 | 86 | echo '
'."\n"; 87 | echo ''; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/includes/traits/Plugin/DirUtils.php: -------------------------------------------------------------------------------- 1 | options['base_dir'])) { 26 | throw new \Exception(__('Missing `base_dir` option value.', SLUG_TD)); 27 | } 28 | $wp_content_base_dir_to = WP_CONTENT_DIR.'/'.$this->options['base_dir']; 29 | 30 | if (isset($rel_dir_file[0])) { 31 | $wp_content_base_dir_to .= '/'.$rel_dir_file; 32 | } 33 | return $wp_content_base_dir_to; 34 | } 35 | 36 | /** 37 | * This constructs a relative/base directory path (no leading/trailing slashes). 38 | * Always relative to {@link \WP_CONTENT_DIR}. Depends on the configured `base_dir` option value. 39 | * 40 | * @since 150422 Rewrite. 41 | * 42 | * @param string $rel_dir_file A sub-directory or file; relative location please. 43 | * 44 | * @throws \Exception If `base_dir` is empty when this method is called upon; 45 | * i.e. if you attempt to call upon this method before {@link setup()} runs. 46 | * 47 | * @return string The relative/base directory path to `$rel_dir_file`. 48 | */ 49 | public function basePathTo($rel_dir_file) 50 | { 51 | $rel_dir_file = trim((string) $rel_dir_file, '\\/'." \t\n\r\0\x0B"); 52 | 53 | if (empty($this->options['base_dir'])) { 54 | throw new \Exception(__('Missing `base_dir` option value.', SLUG_TD)); 55 | } 56 | $base_path_to = $this->options['base_dir']; 57 | 58 | if (isset($rel_dir_file[0])) { 59 | $base_path_to .= '/'.$rel_dir_file; 60 | } 61 | return $base_path_to; 62 | } 63 | 64 | /** 65 | * Get the absolute filesystem path to the root of the WordPress installation. 66 | * 67 | * Copied verbatim from get_home_path() in wp-admin/includes/file.php 68 | * 69 | * @since 151114 Adding `.htaccess` tweaks. 70 | * 71 | * @return string Full filesystem path to the root of the WordPress installation 72 | */ 73 | public function wpHomePath() 74 | { 75 | $home = set_url_scheme(get_option('home'), 'http'); 76 | $siteurl = set_url_scheme(get_option('siteurl'), 'http'); 77 | if (!empty($home) && 0 !== strcasecmp($home, $siteurl) && !empty($_SERVER['SCRIPT_FILENAME'])) { 78 | $wp_path_rel_to_home = preg_replace('/'.preg_quote($home, '/').'/ui', '', $siteurl); /* $siteurl - $home */ 79 | $pos = strripos(str_replace('\\', '/', $_SERVER['SCRIPT_FILENAME']), trailingslashit($wp_path_rel_to_home)); 80 | $home_path = mb_substr($_SERVER['SCRIPT_FILENAME'], 0, $pos); 81 | $home_path = trailingslashit($home_path); 82 | } else { 83 | $home_path = ABSPATH; 84 | } 85 | return str_replace('\\', '/', $home_path); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/includes/traits/Shared/IpAddrUtils.php: -------------------------------------------------------------------------------- 1 | staticKey('currentIp'))) { 21 | return $ip; // Already cached this. 22 | } 23 | $sources = [ 24 | 'HTTP_CF_CONNECTING_IP', 25 | 'HTTP_CLIENT_IP', 26 | 'HTTP_X_FORWARDED_FOR', 27 | 'HTTP_X_FORWARDED', 28 | 'HTTP_X_CLUSTER_CLIENT_IP', 29 | 'HTTP_FORWARDED_FOR', 30 | 'HTTP_FORWARDED', 31 | 'HTTP_VIA', 32 | 'REMOTE_ADDR', 33 | ]; 34 | $sources = $this->applyFilters(GLOBAL_NS.'\\share::current_ip_sources', $sources); 35 | $sources = $this->applyFilters(GLOBAL_NS.'_current_ip_sources', $sources); 36 | 37 | $prioritize_remote_addr = false; // Off by default; can be filtered however. 38 | $prioritize_remote_addr = $this->applyFilters(GLOBAL_NS.'\\share::current_ip_prioritize_remote_addr', $prioritize_remote_addr); 39 | $prioritize_remote_addr = $this->applyFilters(GLOBAL_NS.'_current_ip_prioritize_remote_addr', $prioritize_remote_addr); 40 | 41 | if (!empty($_SERVER['REMOTE_ADDR']) && $prioritize_remote_addr) { 42 | if (($_valid_public_ip = $this->validPublicIp((string) $_SERVER['REMOTE_ADDR']))) { 43 | return $ip = $_valid_public_ip; 44 | } 45 | unset($_valid_public_ip); // Housekeeping. 46 | } 47 | foreach ($sources as $_key => $_source) { 48 | if (!empty($_SERVER[$_source])) { 49 | if (($_valid_public_ip = $this->validPublicIp((string) $_SERVER[$_source]))) { 50 | return $ip = $_valid_public_ip; 51 | } 52 | } 53 | unset($_key, $_source, $_valid_public_ip); // Housekeeping. 54 | } 55 | if (!empty($_SERVER['REMOTE_ADDR'])) { 56 | return $ip = mb_strtolower((string) $_SERVER['REMOTE_ADDR']); 57 | } 58 | return $ip = 'unknown'; // Not possible. 59 | } 60 | 61 | /** 62 | * Gets a valid/public IP address. 63 | * 64 | * @since 150422 Rewrite. 65 | * 66 | * @param string $list_of_possible_ips A single IP, or a comma-delimited list of IPs. 67 | * 68 | * @return string A valid/public IP address (if one is found), else an empty string. 69 | * 70 | * @note This supports both IPv4 and IPv6 addresses. 71 | * @note See my tests against this here: http://3v4l.org/fVWUp 72 | */ 73 | public function validPublicIp($list_of_possible_ips) 74 | { 75 | if (!$list_of_possible_ips || !is_string($list_of_possible_ips)) { 76 | return ''; // Empty or invalid data. 77 | } 78 | if (!($list_of_possible_ips = trim($list_of_possible_ips))) { 79 | return ''; // Not possible; i.e., empty string. 80 | } 81 | foreach (preg_split('/[\s;,]+/', $list_of_possible_ips, -1, PREG_SPLIT_NO_EMPTY) as $_key => $_possible_ip) { 82 | if (($_valid_public_ip = filter_var(mb_strtolower($_possible_ip), FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE))) { 83 | return $_valid_public_ip; // A valid public IPv4 or IPv6 address. 84 | } 85 | } 86 | unset($_key, $_possible_ip, $_valid_public_ip); // Housekeeping. 87 | 88 | return ''; // Default return value. 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/includes/traits/Shared/MemoryUtils.php: -------------------------------------------------------------------------------- 1 | isAdvancedCache()) { 32 | if (COMET_CACHE_MEMCACHED_ENABLE) { 33 | static::$memcached = new Classes\Memcached(COMET_CACHE_MEMCACHED_SERVERS); 34 | } 35 | } elseif ($this->isPlugin()) { 36 | if ($this->options['memcached_enable']) { 37 | static::$memcached = new Classes\Memcached($this->options['memcached_servers']); 38 | } 39 | } 40 | return static::$memcached = isset(static::$memcached) ? static::$memcached : false; 41 | } 42 | 43 | /** 44 | * Memory enabled? 45 | * 46 | * @since 17xxxx Memory utils. 47 | * 48 | * @return bool True if enabled. 49 | */ 50 | public function memEnabled() 51 | { 52 | $instance = $this->memInstance(); 53 | return $enabled = $instance instanceof Classes\Memcached && $instance->enabled(); 54 | } 55 | 56 | /** 57 | * Get cache value by key. 58 | * 59 | * @since 17xxxx Memory utils. 60 | * 61 | * @param string $primary_key Primary key. 62 | * @param string|int $sub_key Sub-key to get. 63 | * 64 | * @return mixed|null Null if missing, or on failure. 65 | */ 66 | public function memGet($primary_key, $sub_key) 67 | { 68 | $instance = $this->memInstance(); 69 | 70 | if ($instance instanceof Classes\Memcached && $instance->enabled()) { 71 | return $instance->get($primary_key, $sub_key); 72 | } 73 | return null; // Not possible. 74 | } 75 | 76 | /** 77 | * Set|update cache key. 78 | * 79 | * @since 17xxxx Memory utils. 80 | * 81 | * @param string $primary_key Primary key. 82 | * @param string|int $sub_key Sub-key to set. 83 | * @param string $value Value to cache (1MB max). 84 | * @param int $expires_in Expires (in seconds). 85 | * 86 | * @return bool True on success. 87 | */ 88 | public function memSet($primary_key, $sub_key, $value, $expires_in = 0) 89 | { 90 | $instance = $this->memInstance(); 91 | 92 | if ($instance instanceof Classes\Memcached && $instance->enabled()) { 93 | return $instance->set($primary_key, $sub_key, $value, $expires_in); 94 | } 95 | return false; // Not possible. 96 | } 97 | 98 | /** 99 | * Clear the cache. 100 | * 101 | * @since 17xxxx Memory utils. 102 | * 103 | * @param string $primary_key Primary key. 104 | * @param string|int|null $sub_key Sub-key (optional). 105 | * @param int $delay Delay (in seconds). 106 | * 107 | * @return bool True on success. 108 | */ 109 | public function memClear($primary_key, $sub_key = null, $delay = 0) 110 | { 111 | $instance = $this->memInstance(); 112 | 113 | if ($instance instanceof Classes\Memcached && $instance->enabled()) { 114 | return $instance->clear($primary_key, $sub_key, $delay); 115 | } 116 | return false; // Not possible. 117 | } 118 | } 119 | /*[/pro]*/ 120 | -------------------------------------------------------------------------------- /src/includes/traits/Plugin/OptionUtils.php: -------------------------------------------------------------------------------- 1 | options = $this->default_options; 19 | return $this->getOptions(); 20 | } 21 | 22 | /** 23 | * Get plugin options. 24 | * 25 | * @since 151002 Improving multisite compat. 26 | * 27 | * @param bool $intersect Discard options not present in $this->default_options 28 | * @param bool $refresh Force-pull options directly from get_site_option() 29 | * 30 | * @return array Plugin options. 31 | * 32 | * @note The `$intersect` param should be `false` when this method is called by a VS upgrade routine. 33 | * Also `false` during inital startup or when upgrading. See: 34 | */ 35 | public function getOptions($intersect = true, $refresh = false) 36 | { 37 | if (!($options = $this->options) || $refresh) { 38 | if (!is_array($options = get_site_option(GLOBAL_NS.'_options'))) { 39 | $options = []; // Force an array of options. 40 | } 41 | if (!$options && is_array($zencache_options = get_site_option('zencache_options'))) { 42 | $options = $zencache_options; 43 | $options['crons_setup'] = $this->default_options['crons_setup']; 44 | $options['latest_pro_version'] = $this->default_options['latest_pro_version']; 45 | } 46 | } // End the collection of all plugin options. 47 | 48 | $this->options = array_merge($this->default_options, $options); 49 | $this->options = $this->applyWpFilters(GLOBAL_NS.'_options', $this->options); 50 | $this->options = $intersect ? array_intersect_key($this->options, $this->default_options) : $this->options; 51 | $this->options = array_map('trim', array_map('strval', $this->options)); 52 | 53 | $this->options['base_dir'] = trim($this->options['base_dir'], '\\/'." \t\n\r\0\x0B"); 54 | if (!$this->options['base_dir'] || mb_strpos(basename($this->options['base_dir']), 'wp-') === 0) { 55 | $this->options['base_dir'] = $this->default_options['base_dir']; 56 | } 57 | return $this->options; // Plugin options. 58 | } 59 | 60 | /** 61 | * Update plugin options. 62 | * 63 | * @since 151002 Improving multisite compat. 64 | * 65 | * @param array $options One or more new options. 66 | * @param bool $intersect Discard options not present in $this->default_options 67 | * 68 | * @return array Plugin options after update. 69 | * 70 | * @note $intersect should be `false` when this method is called via a VS upgrade routine. See https://git.io/viGIK 71 | */ 72 | public function updateOptions(array $options, $intersect = true) 73 | { 74 | if (!IS_PRO) { // Do not save Pro option keys. 75 | $options = array_diff_key($options, $this->pro_only_option_keys); 76 | } 77 | if (!empty($options['base_dir']) && $options['base_dir'] !== $this->options['base_dir']) { 78 | $this->tryErasingAllFilesDirsIn($this->wpContentBaseDirTo('')); 79 | } 80 | if (IS_PRO && !empty($options['pro_update_username']) && !empty($options['pro_update_password'])) { 81 | $this->dismissMainNotice('configure-pro-updater'); 82 | } 83 | $this->options = array_merge($this->default_options, $this->options, $options); 84 | $this->options = $intersect ? array_intersect_key($this->options, $this->default_options) : $this->options; 85 | $this->options = array_map('trim', array_map('strval', $this->options)); 86 | 87 | update_site_option(GLOBAL_NS.'_options', $this->options); 88 | 89 | return $this->getOptions($intersect); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/includes/traits/Ac/HtmlCUtils.php: -------------------------------------------------------------------------------- 1 | content_url) { 24 | return $cache; // Not possible. 25 | } 26 | if (!COMET_CACHE_HTMLC_ENABLE) { 27 | return $cache; // Nothing to do here. 28 | } 29 | if ($this->is_user_logged_in && !COMET_CACHE_HTMLC_WHEN_LOGGED_IN) { 30 | return $cache; // Nothing to do here. 31 | } 32 | // Deals with multisite base & sub-directory installs. 33 | // e.g. `htmlc/cache/public/www-example-com` (standard WP installation). 34 | // e.g. `htmlc/cache/public/[[/base]/child1]/www-example-com` (multisite network). 35 | // Note that `www-example-com` (current host slug) is appended by the HTML compressor. 36 | 37 | $host_base_dir_tokens = $this->hostBaseDirTokens(true); // Dashify this. 38 | 39 | $cache_dir_public = COMET_CACHE_HTMLC_CACHE_DIR_PUBLIC.rtrim($host_base_dir_tokens, '/'); 40 | $cache_dir_url_public = $this->content_url.str_replace(WP_CONTENT_DIR, '', $cache_dir_public); 41 | 42 | $cache_dir_private = COMET_CACHE_HTMLC_CACHE_DIR_PRIVATE.rtrim($host_base_dir_tokens, '/'); 43 | $cache_dir_url_private = $this->content_url.str_replace(WP_CONTENT_DIR, '', $cache_dir_private); 44 | 45 | $benchmark = COMET_CACHE_DEBUGGING_ENABLE >= 2 ? 'details' : COMET_CACHE_DEBUGGING_ENABLE; 46 | $product_title = sprintf(__('%1$s HTML Compressor', SLUG_TD), NAME); 47 | 48 | $html_compressor_options = [ 49 | 'benchmark' => $benchmark, 50 | 'product_title' => $product_title, 51 | 52 | 'cache_dir_public' => $cache_dir_public, 53 | 'cache_dir_url_public' => $cache_dir_url_public, 54 | 55 | 'cache_dir_private' => $cache_dir_private, 56 | 'cache_dir_url_private' => $cache_dir_url_private, 57 | 58 | 'regex_css_exclusions' => COMET_CACHE_HTMLC_CSS_EXCLUSIONS, 59 | 'regex_js_exclusions' => COMET_CACHE_HTMLC_JS_EXCLUSIONS, 60 | 'regex_uri_exclusions' => COMET_CACHE_HTMLC_URI_EXCLUSIONS, 61 | 62 | 'cache_expiration_time' => COMET_CACHE_HTMLC_CACHE_EXPIRATION_TIME, 63 | 64 | 'compress_combine_head_body_css' => COMET_CACHE_HTMLC_COMPRESS_COMBINE_HEAD_BODY_CSS, 65 | 'compress_combine_head_js' => COMET_CACHE_HTMLC_COMPRESS_COMBINE_HEAD_JS, 66 | 'compress_combine_footer_js' => COMET_CACHE_HTMLC_COMPRESS_COMBINE_FOOTER_JS, 67 | 'compress_combine_remote_css_js' => COMET_CACHE_HTMLC_COMPRESS_COMBINE_REMOTE_CSS_JS, 68 | 'compress_inline_js_code' => COMET_CACHE_HTMLC_COMPRESS_INLINE_JS_CODE, 69 | 'compress_css_code' => COMET_CACHE_HTMLC_COMPRESS_CSS_CODE, 70 | 'compress_js_code' => COMET_CACHE_HTMLC_COMPRESS_JS_CODE, 71 | 'compress_html_code' => COMET_CACHE_HTMLC_COMPRESS_HTML_CODE, 72 | 'amp_exclusions_enable' => COMET_CACHE_HTMLC_AMP_EXCLUSIONS_ENABLE, 73 | ]; 74 | try { 75 | $html_compressor = new \WebSharks\HtmlCompressor\Core($html_compressor_options); 76 | $compressed_cache = $html_compressor->compress($cache); 77 | } catch (\Exception $exception) { 78 | $compressed_cache = $cache; // Fail softly. 79 | if (COMET_CACHE_DEBUGGING_ENABLE >= 2) { // Leave a note in the source code? 80 | $compressed_cache .= "\n".''; 81 | } 82 | } 83 | return $compressed_cache.(COMET_CACHE_DEBUGGING_ENABLE ? "\n" : ''); 84 | } 85 | } 86 | /*[/pro]*/ 87 | -------------------------------------------------------------------------------- /src/includes/traits/Plugin/WcpCommentUtils.php: -------------------------------------------------------------------------------- 1 | cacheKey('autoClearCommentPostCache', $comment_id))) { 29 | return $counter; // Already did this. 30 | } 31 | $done = true; // Flag as having been done. 32 | 33 | if (!$this->options['enable']) { 34 | return $counter; // Nothing to do. 35 | } 36 | if (!is_object($comment = get_comment($comment_id))) { 37 | return $counter; // Nothing we can do. 38 | } 39 | if (empty($comment->comment_post_ID)) { 40 | return $counter; // Nothing we can do. 41 | } 42 | if ($comment->comment_approved === 'spam' || $comment->comment_approved === '0') { 43 | // Don't allow next `autoClearPostCache()` call to clear post cache. 44 | $allow = &$this->cacheKey('autoClearPostCache_allow'); 45 | $allow = false; // Flag as false; i.e., disallow. 46 | return $counter; 47 | } 48 | $counter += $this->autoClearXmlFeedsCache('blog-comments'); 49 | $counter += $this->autoClearXmlFeedsCache('post-comments', $comment->comment_post_ID); 50 | $counter += $this->autoClearPostCache($comment->comment_post_ID); 51 | 52 | return $counter; 53 | } 54 | 55 | /** 56 | * Automatically clears cache files for a post associated with a particular comment. 57 | * 58 | * @since 150422 Rewrite. 59 | * 60 | * @attaches-to `transition_comment_status` hook. 61 | * 62 | * @param string $new_status New comment status. 63 | * @param string $old_status Old comment status. 64 | * @param \stdClass $comment Comment object. 65 | * 66 | * @throws \Exception If a clear failure occurs. 67 | * 68 | * @return int Total files cleared by this routine (if any). 69 | * 70 | * @note This is also called upon by other routines which listen for 71 | * events that are indirectly associated with a comment ID. 72 | */ 73 | public function autoClearCommentPostCacheTransition($new_status, $old_status, $comment) 74 | { 75 | $counter = 0; // Initialize. 76 | 77 | if (!is_object($comment)) { 78 | return $counter; // Nothing we can do. 79 | } 80 | if (empty($comment->comment_post_ID)) { 81 | return $counter; // Nothing we can do. 82 | } 83 | if (!is_null($done = &$this->cacheKey('autoClearCommentPostCacheTransition', [$new_status, $old_status, $comment->comment_post_ID]))) { 84 | return $counter; // Already did this. 85 | } 86 | $done = true; // Flag as having been done. 87 | 88 | if (!$this->options['enable']) { 89 | return $counter; // Nothing to do. 90 | } 91 | if (!($old_status === 'approved' || ($old_status === 'unapproved' && $new_status === 'approved'))) { 92 | // If excluded here, don't allow next `autoClearPostCache()` call to clear post cache. 93 | $allow = &$this->cacheKey('autoClearPostCache_allow'); 94 | $allow = false; // Flag as false; i.e., disallow. 95 | return $counter; 96 | } 97 | $counter += $this->autoClearXmlFeedsCache('blog-comments'); 98 | $counter += $this->autoClearXmlFeedsCache('post-comments', $comment->comment_post_ID); 99 | $counter += $this->autoClearPostCache($comment->comment_post_ID); 100 | 101 | return $counter; 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/includes/traits/Plugin/WcpHomeBlogUtils.php: -------------------------------------------------------------------------------- 1 | cacheKey('autoClearHomePageCache'))) { 25 | return $counter; // Already did this. 26 | } 27 | $done = true; // Flag as having been done. 28 | 29 | if (!$this->options['enable']) { 30 | return $counter; // Nothing to do. 31 | } 32 | if (!$this->options['cache_clear_home_page_enable']) { 33 | return $counter; // Nothing to do. 34 | } 35 | if (!is_dir($cache_dir = $this->cacheDir())) { 36 | return $counter; // Nothing to do. 37 | } 38 | $regex = $this->buildHostCachePathRegex(home_url('/')); 39 | $counter += $this->clearFilesFromHostCacheDir($regex); 40 | 41 | if ($counter && is_admin() && (!IS_PRO || $this->options['change_notifications_enable'])) { 42 | $this->enqueueNotice(sprintf(__('Found %1$s in the cache for the designated "Home Page"; auto-clearing.', SLUG_TD), esc_html($this->i18nFiles($counter))), ['combinable' => true]); 43 | } 44 | $counter += $this->autoClearXmlFeedsCache('blog'); 45 | 46 | return $counter; 47 | } 48 | 49 | /** 50 | * Automatically clears cache files for the posts page. 51 | * 52 | * @since 150422 Rewrite. 53 | * 54 | * @throws \Exception If a clear failure occurs. 55 | * 56 | * @return int Total files cleared by this routine (if any). 57 | * 58 | * @note Unlike many of the other `auto_` methods, this one is NOT currently 59 | * attached to any hooks. However, it is called upon by {@link autoClearPostCache()}. 60 | */ 61 | public function autoClearPostsPageCache() 62 | { 63 | $counter = 0; // Initialize. 64 | 65 | if (!is_null($done = &$this->cacheKey('autoClearPostsPageCache'))) { 66 | return $counter; // Already did this. 67 | } 68 | $done = true; // Flag as having been done. 69 | 70 | if (!$this->options['enable']) { 71 | return $counter; // Nothing to do. 72 | } 73 | if (!$this->options['cache_clear_posts_page_enable']) { 74 | return $counter; // Nothing to do. 75 | } 76 | if (!is_dir($cache_dir = $this->cacheDir())) { 77 | return $counter; // Nothing to do. 78 | } 79 | $show_on_front = get_option('show_on_front'); 80 | $page_for_posts = get_option('page_for_posts'); 81 | 82 | if (!in_array($show_on_front, ['posts', 'page'], true)) { 83 | return $counter; // Nothing we can do in this case. 84 | } 85 | if ($show_on_front === 'page' && !$page_for_posts) { 86 | return $counter; // Nothing we can do. 87 | } 88 | if ($show_on_front === 'posts') { 89 | $posts_page = home_url('/'); 90 | } elseif ($show_on_front === 'page') { 91 | $posts_page = get_permalink($page_for_posts); 92 | } 93 | if (empty($posts_page)) { 94 | return $counter; // Nothing we can do. 95 | } 96 | $regex = $this->buildHostCachePathRegex($posts_page); 97 | $counter += $this->clearFilesFromHostCacheDir($regex); 98 | 99 | if ($counter && is_admin() && (!IS_PRO || $this->options['change_notifications_enable'])) { 100 | $this->enqueueNotice(sprintf(__('Found %1$s in the cache for the designated "Posts Page"; auto-clearing.', SLUG_TD), esc_html($this->i18nFiles($counter))), ['combinable' => true]); 101 | } 102 | $counter += $this->autoClearXmlFeedsCache('blog'); 103 | 104 | return $counter; 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/includes/traits/Plugin/CronUtils.php: -------------------------------------------------------------------------------- 1 | 900, 23 | 'display' => __('Every 15 Minutes', SLUG_TD), 24 | ]; 25 | return $schedules; 26 | } 27 | 28 | /** 29 | * Checks cron setup, validates schedules, and reschedules events if necessary. 30 | * 31 | * @attaches-to `init` hook. 32 | * 33 | * @since 151220 Improving WP Cron setup and validation of schedules 34 | */ 35 | public function checkCronSetup() 36 | { 37 | if ((!get_transient('doing_cron') && $this->options['crons_setup'] < 1439005906) 38 | || $this->options['crons_setup_on_namespace'] !== __NAMESPACE__ 39 | || $this->options['crons_setup_with_cache_cleanup_schedule'] !== $this->options['cache_cleanup_schedule'] 40 | || $this->options['crons_setup_on_wp_with_schedules'] !== sha1(serialize(wp_get_schedules())) 41 | || !wp_next_scheduled('_cron_'.GLOBAL_NS.'_cleanup') 42 | /*[pro strip-from="lite"]*/ // Auto-cache engine. 43 | || !wp_next_scheduled('_cron_'.GLOBAL_NS.'_auto_cache') 44 | /*[/pro]*/ 45 | ) { 46 | wp_clear_scheduled_hook('_cron_'.GLOBAL_NS.'_cleanup'); 47 | wp_schedule_event(time() + 60, $this->options['cache_cleanup_schedule'], '_cron_'.GLOBAL_NS.'_cleanup'); 48 | 49 | /*[pro strip-from="lite"]*/ // Auto-cache engine. 50 | wp_clear_scheduled_hook('_cron_'.GLOBAL_NS.'_auto_cache'); 51 | wp_schedule_event(time() + 60, 'every15m', '_cron_'.GLOBAL_NS.'_auto_cache'); 52 | /*[/pro]*/ 53 | 54 | $this->updateOptions( 55 | [ 56 | 'crons_setup' => time(), 57 | 'crons_setup_on_namespace' => __NAMESPACE__, 58 | 'crons_setup_with_cache_cleanup_schedule' => $this->options['cache_cleanup_schedule'], 59 | 'crons_setup_on_wp_with_schedules' => sha1(serialize(wp_get_schedules())), 60 | ] 61 | ); 62 | } 63 | } 64 | 65 | /** 66 | * Resets `crons_setup` and clears WP-Cron schedules. 67 | * 68 | * @since 151220 Fixing bug with Auto-Cache Engine cron disappearing in some scenarios 69 | * 70 | * @note This MUST happen upon uninstall and deactivation due to buggy WP_Cron behavior. 71 | * Events with a custom schedule will disappear when plugin is not active (see http://bit.ly/1lGdr78). 72 | */ 73 | public function resetCronSetup() 74 | { 75 | if (is_multisite()) { // Main site CRON jobs. 76 | switch_to_blog(get_current_site()->blog_id); 77 | /*[pro strip-from="lite"]*/ // Auto-cache engine. 78 | wp_clear_scheduled_hook('_cron_'.GLOBAL_NS.'_auto_cache'); 79 | /*[/pro]*/ 80 | wp_clear_scheduled_hook('_cron_'.GLOBAL_NS.'_cleanup'); 81 | restore_current_blog(); // Restore current blog. 82 | } else { // Standard WP installation. 83 | /*[pro strip-from="lite"]*/ // Auto-cache engine. 84 | wp_clear_scheduled_hook('_cron_'.GLOBAL_NS.'_auto_cache'); 85 | /*[/pro]*/ 86 | wp_clear_scheduled_hook('_cron_'.GLOBAL_NS.'_cleanup'); 87 | } 88 | $this->updateOptions( 89 | [ // Reset so that crons are rescheduled upon next activation 90 | 'crons_setup' => $this->default_options['crons_setup'], 91 | 'crons_setup_on_namespace' => $this->default_options['crons_setup_on_namespace'], 92 | 'crons_setup_with_cache_cleanup_schedule' => $this->default_options['crons_setup_with_cache_cleanup_schedule'], 93 | 'crons_setup_on_wp_with_schedules' => $this->default_options['crons_setup_on_wp_with_schedules'], 94 | ] 95 | ); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/client-s/css/menu-pages/_panels.scss: -------------------------------------------------------------------------------- 1 | .plugin-menu-page-panel { 2 | margin: 1em 0; 3 | 4 | &:first-child { 5 | margin-top: 0; 6 | } 7 | 8 | .plugin-menu-page-panel-heading { 9 | @include user-select(none); 10 | @include sharkicon(chevron-down, after); 11 | 12 | text-decoration: none; 13 | padding: 10px; 14 | font-size: 150%; 15 | line-height: 1.125em; 16 | font-weight: 600; 17 | border-radius: 4px; 18 | display: block; 19 | cursor: pointer; 20 | background: $panel-heading-bg-color; 21 | background: linear-gradient(to right, $panel-heading-bg-color, $panel-heading-bg-color-fade); 22 | color: $panel-heading-color !important; 23 | box-shadow: 0 2px 2px 0 $panel-heading-box-shadow-color; 24 | 25 | &:hover, 26 | &.open { 27 | color: $panel-heading-hover-color !important; 28 | } 29 | 30 | &::after { 31 | font-size: 80%; 32 | float: right; 33 | margin: 0 0 0 5px; 34 | } 35 | 36 | &.open::after { 37 | content: map-get($sharkicons, chevron-up); 38 | } 39 | 40 | @at-root [data-pro-version-only*=' '] { 41 | @at-root .plugin-menu-page-panel-heading[data-pro-version-only*=' '] { 42 | background: #216095; 43 | } 44 | 45 | &::after { 46 | font-variant: small-caps !important; 47 | font-family: sans-serif !important; 48 | content: attr(data-pro-version-only) !important; 49 | margin-left: 15px; 50 | background: #216095; 51 | color: #FFFFFF; 52 | padding: 0 5px 2px 5px; 53 | font-weight: normal; 54 | } 55 | } 56 | 57 | @at-root [data-additional-pro-features*=' '] { 58 | @at-root .plugin-menu-page-panel-heading[data-additional-pro-features*=' '] { 59 | background: #216095; 60 | } 61 | 62 | &::after { 63 | font-variant: small-caps !important; 64 | font-family: sans-serif !important; 65 | content: attr(data-additional-pro-features) !important; 66 | margin-left: 15px; 67 | background: #216095; 68 | color: #FFFFFF; 69 | padding: 0 5px 2px 5px; 70 | font-weight: normal; 71 | } 72 | } 73 | 74 | > .si { 75 | text-align: center; 76 | width: 1.28571429em; 77 | margin-right: .25em; 78 | } 79 | } 80 | 81 | .plugin-menu-page-panel-body { 82 | width: 99%; 83 | margin: 0 auto; 84 | display: none; 85 | padding: 1.2em; 86 | border-bottom-left-radius: 4px; 87 | border-bottom-right-radius: 4px; 88 | box-sizing: border-box; 89 | color: $panel-body-color; 90 | border: 1px solid $panel-body-border-color; 91 | background: $panel-body-bg-color; 92 | box-shadow: 0 1px 1px 0 $panel-body-box-shadow-color-a, 0 3px 1px -1px $panel-body-box-shadow-color-b inset; 93 | 94 | &.open { 95 | display: block; 96 | } 97 | 98 | p { 99 | font-size: 13px; 100 | color: $panel-body-p-color; 101 | } 102 | 103 | p.speed { 104 | font-size: 120%; 105 | font-weight: bold; 106 | float: right; 107 | 108 | @media (max-width: 1199px) { 109 | display: none; 110 | } 111 | } 112 | 113 | p.notice, 114 | p.info, 115 | p.warning, 116 | p.error { 117 | color: $panel-body-p-notice-color; 118 | } 119 | 120 | h3 { 121 | margin: 0 0 0.5em; 122 | } 123 | 124 | h3:first-child { 125 | margin-top: 0; 126 | } 127 | 128 | h3 + p { 129 | margin-top: 0; 130 | } 131 | 132 | a.dotted { 133 | text-decoration: none; 134 | border-bottom: 1px dotted; 135 | } 136 | 137 | &.pro-preview, 138 | .pro-preview { 139 | opacity: 0.5; 140 | } 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /src/client-s/css/admin-bar/_wipe-clear.scss: -------------------------------------------------------------------------------- 1 | /*[pro strip-from='lite']*/ 2 | 3 | $clear-options-split-border-color: rgb(88, 88, 88); 4 | 5 | #wp-admin-bar-comet_cache-wipe, 6 | #wp-admin-bar-comet_cache-clear { 7 | > a { 8 | &::after { 9 | border: 0; 10 | padding: 0; 11 | content: ' '; 12 | width: 16px; 13 | height: 16px; 14 | line-height: 16px; 15 | vertical-align: middle; 16 | margin: -3px 0 0 5px; 17 | display: inline-block; 18 | } 19 | } 20 | 21 | &.-wipe { 22 | > a { 23 | &::after { 24 | content: url('../images/wipe.png'); 25 | } 26 | } 27 | } 28 | 29 | &.-clear { 30 | > a { 31 | &::after { 32 | content: url('../images/clear.png'); 33 | } 34 | } 35 | } 36 | 37 | &.-processing { 38 | > a { 39 | &::after { 40 | @include comet_cache-admin-bar-animation-spin; 41 | 42 | content: url('../images/spinner.png'); 43 | } 44 | } 45 | } 46 | } 47 | 48 | #wp-admin-bar-comet_cache-clear-options-wrapper { 49 | &.-wrapper, 50 | .-container, 51 | .-container > div { 52 | margin: 0 !important; 53 | padding: 0 !important; 54 | display: block !important; 55 | white-space: normal !important; 56 | width: 100% !important; 57 | min-width: 100% !important; 58 | height: auto !important; 59 | line-height: normal !important; 60 | box-sizing: border-box !important; 61 | } 62 | 63 | &.-wrapper { 64 | padding: 1em !important; 65 | 66 | .-container { 67 | * { 68 | margin: 0; 69 | padding: 0; 70 | width: auto; 71 | height: auto; 72 | position: static; 73 | line-height: normal; 74 | box-sizing: border-box; 75 | } 76 | 77 | .-label { 78 | margin: 0 0 1em; 79 | 80 | &::after { 81 | border: 0; 82 | padding: 0; 83 | width: 16px; 84 | height: 16px; 85 | float: right; 86 | vertical-align: middle; 87 | display: inline-block; 88 | content: url('../images/clear.png'); 89 | } 90 | 91 | .-text { 92 | opacity: 0.75; 93 | } 94 | 95 | &.-processing::after { 96 | @include comet_cache-admin-bar-animation-spin; 97 | 98 | content: url('../images/spinner.png'); 99 | } 100 | } 101 | 102 | .-options { 103 | > li > a { 104 | &::before { 105 | padding-right: .5em; 106 | text-align: center; 107 | width: 1.28571429em; 108 | } 109 | } 110 | 111 | .-home-url-only { 112 | > a { 113 | @include sharkicon(home); 114 | } 115 | } 116 | 117 | .-current-url-only { 118 | > a { 119 | @include sharkicon(file-text-o); 120 | } 121 | } 122 | 123 | .-specific-url-only { 124 | > a { 125 | @include sharkicon(chain); 126 | } 127 | } 128 | 129 | .-opcache-only { 130 | > a { 131 | @include sharkicon(feat-layers); 132 | } 133 | } 134 | 135 | .-cdn-only { 136 | > a { 137 | @include sharkicon(cloud); 138 | } 139 | } 140 | 141 | .-transients-only { 142 | > a { 143 | @include sharkicon(feat-server); 144 | } 145 | } 146 | } 147 | 148 | .-spacer { 149 | min-width: 145px; 150 | } 151 | } 152 | } 153 | } 154 | 155 | #wp-admin-bar-comet_cache-clear-options { 156 | border-left: 1px solid $clear-options-split-border-color; 157 | border-right: 1px solid $clear-options-split-border-color; 158 | 159 | > a { 160 | @include sharkicon(chevron-down, after); 161 | } 162 | 163 | .-wrapper { 164 | .-container { 165 | .-spacer { 166 | min-width: 145px; 167 | } 168 | } 169 | } 170 | } 171 | 172 | /*[/pro]*/ 173 | -------------------------------------------------------------------------------- /src/includes/classes/Conflicts.php: -------------------------------------------------------------------------------- 1 | '.// Error notice. 96 | '

'.// Running one or more conflicting plugins at the same time. 97 | ' '.sprintf(__('%1$s is NOT running. A conflicting plugin, %2$s, is currently active. Please deactivate the %2$s plugin to clear this message.', SLUG_TD), esc_html($this_plugin_name), esc_html($conflicting_plugin_name)). 98 | '

'. 99 | ''; 100 | }); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/includes/traits/Plugin/WcpDateArchiveUtils.php: -------------------------------------------------------------------------------- 1 | cacheKey('autoClearDateArchiveCache', [$post_id, $force]))) { 34 | return $counter; // Already did this. 35 | } 36 | $done = true; // Flag as having been done. 37 | 38 | if (!$this->options['enable']) { 39 | return $counter; // Nothing to do. 40 | } 41 | if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) { 42 | return $counter; // Nothing to do. 43 | } 44 | if (!$this->options['cache_clear_date_archives_enable']) { 45 | return $counter; // Nothing to do. 46 | } 47 | if (!is_dir($cache_dir = $this->cacheDir())) { 48 | return $counter; // Nothing to do. 49 | } 50 | $post_status = get_post_status($post_id); // Cache this. 51 | 52 | if ($post_status === 'draft' && isset($GLOBALS['pagenow'], $_POST['publish']) 53 | && is_admin() && $GLOBALS['pagenow'] === 'post.php' && current_user_can('publish_posts') 54 | && mb_strpos(wp_get_referer(), '/post-new.php') !== false 55 | ) { 56 | $post_status = 'publish'; // A new post being published now. 57 | } 58 | if (in_array($post_status, ['inherit', 'auto-draft'], true)) { 59 | return $counter; // Nothing to do. Note: `inherit` = revision. 60 | } 61 | if (in_array($post_status, ['draft', 'pending', 'future'], true) && !$force) { 62 | return $counter; // Nothing to do; i.e., NOT forcing in this case. 63 | } 64 | $date_archive_urls = []; // Initialize archive urls. 65 | $publish_time = get_post_time('U', true, $post_id); 66 | 67 | $Y = date('Y', $publish_time); 68 | $m = date('m', $publish_time); 69 | $j = date('j', $publish_time); 70 | 71 | if ($this->options['cache_clear_date_archives_enable'] === '1') { 72 | $date_archive_urls[sprintf(__('%1$s Date Archive', SLUG_TD), $Y)] = get_year_link($Y); 73 | $date_archive_urls[sprintf(__('%1$s/%2$s Date Archive', SLUG_TD), $Y, $m)] = get_month_link($Y, $m); 74 | $date_archive_urls[sprintf(__('%1$s/%2$s/%3$s Date Archive', SLUG_TD), $Y, $m, $j)] = get_day_link($Y, $m, $j); 75 | } elseif ($this->options['cache_clear_date_archives_enable'] === '2') { 76 | $date_archive_urls[sprintf(__('%1$s/%2$s Date Archive', SLUG_TD), $Y, $m)] = get_month_link($Y, $m); 77 | $date_archive_urls[sprintf(__('%1$s/%2$s/%3$s Date Archive', SLUG_TD), $Y, $m, $j)] = get_day_link($Y, $m, $j); 78 | } else { // Assume $this->options['cache_clear_date_archives_enable'] === '3' 79 | $date_archive_urls[sprintf(__('%1$s/%2$s/%3$s Date Archive', SLUG_TD), $Y, $m, $j)] = get_day_link($Y, $m, $j); 80 | } 81 | foreach ($date_archive_urls as $_label => $_url) { 82 | $_url_regex = $this->buildHostCachePathRegex($_url); 83 | $_url_counter = $this->clearFilesFromHostCacheDir($_url_regex); 84 | $counter += $_url_counter; // Add to overall counter. 85 | 86 | if ($_url_counter && $enqueued_notices < 100 && is_admin() && (!IS_PRO || $this->options['change_notifications_enable'])) { 87 | $this->enqueueNotice(sprintf(__('Found %1$s in the cache for %2$s; auto-clearing.', SLUG_TD), esc_html($this->i18nFiles($_url_counter)), esc_html($_label)), ['combinable' => true]); 88 | ++$enqueued_notices; // Increment enqueued notices counter. 89 | } 90 | } // unset($_label, $_url, $_url_regex, $_url_counter); // Housekeeping. 91 | 92 | return $counter; 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/includes/traits/Shared/UrlUtils.php: -------------------------------------------------------------------------------- 1 | -1) { 28 | if (${'//'} && $component === PHP_URL_SCHEME) { 29 | return $part = '//'; 30 | } 31 | return $part = parse_url($url_uri_qsl, $component); 32 | } else { 33 | if (!is_array($parts = parse_url($url_uri_qsl))) { 34 | return $parts = []; 35 | } 36 | if (${'//'}) { 37 | $parts['scheme'] = '//'; 38 | } 39 | return $parts; 40 | } 41 | } 42 | 43 | /** 44 | * Unparses a URL. 45 | * 46 | * @since 150821 Improving multisite compat. 47 | * 48 | * @param array $parts Input URL parts. 49 | * 50 | * @return string Unparsed URL in string format. 51 | */ 52 | public function unParseUrl(array $parts) 53 | { 54 | $scheme = ''; 55 | $host = ''; 56 | $port = ''; 57 | $user = ''; 58 | $pass = ''; 59 | $path = ''; 60 | $query = ''; 61 | $fragment = ''; 62 | 63 | if (!empty($parts['scheme'])) { 64 | if ($parts['scheme'] === '//') { 65 | $scheme = $parts['scheme']; 66 | } else { 67 | $scheme = $parts['scheme'].'://'; 68 | } 69 | } 70 | if (!empty($parts['host'])) { 71 | $host = $parts['host']; 72 | } 73 | if (!empty($parts['port'])) { 74 | $port = ':'.$parts['port']; 75 | } 76 | if (!empty($parts['user'])) { 77 | $user = $parts['user']; 78 | } 79 | if (!empty($parts['pass'])) { 80 | $pass = $parts['pass']; 81 | } 82 | if ($user || $pass) { 83 | $pass .= '@'; 84 | } 85 | if (!empty($parts['path'])) { 86 | $path = '/'.ltrim($parts['path'], '/'); 87 | } 88 | if (!empty($parts['query'])) { 89 | $query = '?'.$parts['query']; 90 | } 91 | if (!empty($parts['fragment'])) { 92 | $fragment = '#'.$parts['fragment']; 93 | } 94 | return $scheme.$user.$pass.$host.$port.$path.$query.$fragment; 95 | } 96 | 97 | /** 98 | * Is the current request over SSL? 99 | * 100 | * @since 150422 Rewrite. 101 | * 102 | * @return bool `TRUE` if the current request is over SSL. 103 | * 104 | * @note The return value of this function is cached to reduce overhead on repeat calls. 105 | */ 106 | public function isSsl() 107 | { 108 | if (!is_null($is = &$this->staticKey('isSsl'))) { 109 | return $is; // Already cached this. 110 | } 111 | if (!empty($_SERVER['SERVER_PORT'])) { 112 | if ((integer) $_SERVER['SERVER_PORT'] === 443) { 113 | return $is = true; 114 | } 115 | } 116 | if (!empty($_SERVER['HTTPS'])) { 117 | if (filter_var($_SERVER['HTTPS'], FILTER_VALIDATE_BOOLEAN)) { 118 | return $is = true; 119 | } 120 | } 121 | if (!empty($_SERVER['HTTP_X_FORWARDED_PROTO'])) { 122 | if (strcasecmp((string) $_SERVER['HTTP_X_FORWARDED_PROTO'], 'https') === 0) { 123 | return $is = true; 124 | } 125 | } 126 | return $is = false; 127 | } 128 | 129 | /** 130 | * Current URL. 131 | * 132 | * @since 150821 Improving multisite compat. 133 | * 134 | * @return string Current URL. 135 | */ 136 | public function currentUrl() 137 | { 138 | if (empty($_SERVER['HTTP_HOST']) || empty($_SERVER['REQUEST_URI'])) { 139 | return ''; // Not possible. 140 | } 141 | return ($this->isSsl() ? 'https://' : 'http://').$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']; 142 | } 143 | } 144 | --------------------------------------------------------------------------------