Comet Cache - Version 160706

Version Description

= v160416 =

Requires WordPress v4.2+.

Download this release

Release Info

Developer raamdev
Plugin Icon 128x128 Comet Cache
Version 160706
Comparing to
See all releases

Code changes from version 160521 to 160706

Files changed (58) hide show
  1. CHANGELOG.md +27 -0
  2. comet-cache.php +2 -2
  3. plugin.php +5 -4
  4. readme.txt +52 -44
  5. src/client-s/css/menu-pages.min.css +1 -1
  6. src/client-s/images/apache.png +0 -0
  7. src/client-s/images/stats-preview.png +0 -0
  8. src/client-s/js/menu-pages.js +3 -2
  9. src/client-s/js/menu-pages.min.js +2 -2
  10. src/includes/classes/Actions.php +3 -2
  11. src/includes/classes/AdvCacheBackCompat.php +17 -3
  12. src/includes/classes/AdvancedCache.php +1 -1
  13. src/includes/classes/Conflicts.php +3 -3
  14. src/includes/classes/FeedUtils.php +7 -7
  15. src/includes/classes/MenuPageOptions.php +186 -67
  16. src/includes/classes/Plugin.php +15 -1
  17. src/includes/classes/VsUpgrades.php +43 -7
  18. src/includes/interfaces/Shared/NcDebugConsts.php +9 -0
  19. src/includes/stub.php +2 -2
  20. src/includes/templates/ac-plugin.txt +2 -2
  21. src/includes/templates/advanced-cache.txt +13 -2
  22. src/includes/templates/gzip-htaccess.txt +0 -10
  23. src/includes/templates/htaccess/access-control-allow-origin-enable.txt +6 -0
  24. src/includes/templates/htaccess/browser-caching-enable.txt +7 -0
  25. src/includes/templates/htaccess/canonical-urls-no-ts-enable.txt +18 -0
  26. src/includes/templates/htaccess/canonical-urls-ts-enable.txt +18 -0
  27. src/includes/templates/htaccess/gzip-enable.txt +11 -0
  28. src/includes/traits/Ac/{BrowserUtils.php → ClientSideUtils.php} +12 -8
  29. src/includes/traits/Ac/NcDebugUtils.php +5 -1
  30. src/includes/traits/Ac/ObUtils.php +12 -8
  31. src/includes/traits/Plugin/CronUtils.php +1 -1
  32. src/includes/traits/Plugin/DirUtils.php +3 -3
  33. src/includes/traits/Plugin/HtaccessUtils.php +51 -13
  34. src/includes/traits/Plugin/InstallUtils.php +24 -24
  35. src/includes/traits/Plugin/MenuPageUtils.php +3 -3
  36. src/includes/traits/Plugin/NoticeUtils.php +1 -1
  37. src/includes/traits/Plugin/OptionUtils.php +1 -1
  38. src/includes/traits/Plugin/WcpPostUtils.php +1 -1
  39. src/includes/traits/Plugin/WcpSettingUtils.php +2 -0
  40. src/includes/traits/Plugin/WcpTermUtils.php +1 -1
  41. src/includes/traits/Shared/CacheDirUtils.php +25 -13
  42. src/includes/traits/Shared/CachePathUtils.php +10 -10
  43. src/includes/traits/Shared/ConditionalUtils.php +14 -14
  44. src/includes/traits/Shared/DomainMappingUtils.php +7 -7
  45. src/includes/traits/Shared/FsUtils.php +13 -13
  46. src/includes/traits/Shared/HookUtils.php +8 -8
  47. src/includes/traits/Shared/HttpUtils.php +4 -4
  48. src/includes/traits/Shared/IpAddrUtils.php +2 -2
  49. src/includes/traits/Shared/PatternUtils.php +4 -4
  50. src/includes/traits/Shared/ReplaceUtils.php +9 -3
  51. src/includes/traits/Shared/ServerUtils.php +5 -5
  52. src/includes/traits/Shared/StringUtils.php +10 -10
  53. src/includes/traits/Shared/TokenUtils.php +19 -16
  54. src/includes/traits/Shared/UrlUtils.php +5 -2
  55. src/vendor/autoload.php +1 -1
  56. src/vendor/composer/autoload_classmap.php +77 -0
  57. src/vendor/composer/autoload_real.php +3 -3
  58. src/vendor/composer/installed.json +0 -62
CHANGELOG.md CHANGED
@@ -1,3 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  = v160521 =
2
 
3
  - **Bug Fix**: Fixed a bug that, in some scenarios, resulted in "PHP Fatal error: Undefined class constant 'CACHE_PATH_NO_PATH_INDEX'". This also affected the Cache Statistics feature (Comet Cache Pro), resulting in a blank panel when hovering over the Cache Stats button in the menu bar. See [Issue #752](https://github.com/websharks/comet-cache/issues/752).
1
+ = v160706 =
2
+
3
+ - **New Feature! Apache Optimizations.** This release includes a completely new option panel for Apache Performance Tuning. Current options for Apache tuning include GZIP Compression, Leverage Browser Caching, Enforce Canonical URLs, and Send Access-Control-Allow-Origin Header (for Static CDN Filters). These options automatically add or remove from your `.htaccess` file the appropriate configuration based on the options you enable or disable (all options are disabled by default, so your `.htaccess` file is not modified unless you say so). If you prefer to update your `.htaccess` file manually, the necessary configuration can be viewed beneath each option. Props @jaswsinc, @renzms. See [Issue #789](https://github.com/websharks/comet-cache/issues/789).
4
+ - **New Feature!** A new "Enable GZIP Compression" option has been added to the new Apache Optimizations panel. This option will automatically add the appropriate configuration to your `.htaccess` file to enable GZIP compression. This option is disabled by default. The old "GZIP Compression" panel has been removed in favor of the new option inside Apache Optimizations. Props @renzms, @jaswsinc. See [Issue #764](https://github.com/websharks/comet-cache/issues/764).
5
+ - **New Feature!** Multisite Host Exclusion Patterns. It's now possible to exclude entire sites from the cache in a Multisite Network environment. Domain mapping is also supported! See _Comet Cache → Plugin Options → Host Exclusion Patterns_. If you're running a Multisite Network with Sub-Directories, you can exclude sites using the existing URI Exclusion Patterns feature. Props @kristineds. See [Issue #754](https://github.com/websharks/comet-cache/issues/754).
6
+ - **New Feature (Pro)!** A new "Leverage Browser Caching" option has been added to the new Apache Optimizations panel. This option will automatically add the appropriate configuration to your `.htaccess` file to enable Browser Caching. This option is disabled by default. Props @renzms, @jaswsinc. See [Issue #764](https://github.com/websharks/comet-cache/issues/764).
7
+ - **New Feature (Pro)!** A new "Enforce Canonical URLs" option has been added to the new Apache Optimizations panel. This options adds the appropriate `.htaccess` code to enforce the correct canonical URLs according to your WordPress Permalink settings (Comet Cache detects if the Permalink Structure ends with a trailing slash, or without a trailing slash). Props @renzms, @jaswsinc. See [Issue #554](https://github.com/websharks/comet-cache/issues/554).
8
+ - **Bug Fix**: In some scenarios the Cron Event that cleans up expired cache files (`_cron_comet_cache_cleanup`) would never run, or the Next Run time would constantly reset to 1 minute away from running every time a page was reloaded. We suspect this is a race condition and in attempt to work around this issue we now skip all of our Cron-related checks if Cron is currently in the middle of running a process. Props @xberg and @lkraav for help reporting. See [Issue #653](https://github.com/websharks/comet-cache/issues/653).
9
+ - **Bug Fix**: If your site uses aliased domains, Comet Cache now properly considers all possible domain variations when it clears the cache on WP Standard installations. Props @kristineds, @jaswsinc, @yoffe, and @VR51. See [Issue #608](https://github.com/websharks/comet-cache/issues/608).
10
+ - **Bug Fix** (Pro): Fixed a bug where Comet Cache would appear to prevent WordPress from redirecting Permalinks that don't include a trailing slash, to the URL that does include a trailing slash. This was due to the fact that Comet Cache loads very early on (for caching purposes) and as a result the WordPress `redirect_canonical()` function never gets run. This was fixed by adding an option to the new Apache Optimizations panel that allows you to Enforce Canonical URLs. Props @renzms, @jaswsinc. See [Issue #554](https://github.com/websharks/comet-cache/issues/554).
11
+ - **UX Bug Fix** (Pro): If you had your WordPress Dashboard login details saved by your browser, the browser autofill would automatically fill in the Pro Plugin Updater fields with those details, which then needed to be replaced with your actual Pro license details. The browser autofill has been disabled for those fields (tested in Chrome, Firefox, and Safari). Props @renzms. See [Issue #741](https://github.com/websharks/comet-cache/issues/741).
12
+ - **Enhancement**: Added links the Options Page for the Comet Cache [Twitter](http://twitter.com/cometcache) and [Facebook](http://facebook.com/cometcache) accounts. Props @renzms. [Issue #771](https://github.com/websharks/comet-cache/issues/771).
13
+ - **Enhancement:** Added full support for UTF-8 (multibyte strings). This release adds full support for UTF-8 throughout the Comet Cache codebase, greatly enhancing Comet Cache's ability to deal with file paths and URLs that may contain UTF-8 characters. Props @jaswsinc. [Issue #703](https://github.com/websharks/comet-cache/issues/703).
14
+ - **UI Enhancements**: Improved the Logged-In Users and the Client-Side Caching options panels to dim additional options when the feature is disabled. Additionally, the "Enable HTML Compression for Logged-In Users?" option has been relocated from the HTML Compressor option panel to the more appropriate Logged-In Users option panel. See [Issue #768](https://github.com/websharks/comet-cache/issues/768).
15
+ - **UX Enhancement**: Improved the inline docs for Auto-Clear List of Custom URLs to clarify that full URLs must be provided. Props @renzms. See [Issue #781](https://github.com/websharks/comet-cache/issues/781).
16
+ - **Enhancement** (Pro): The Pro Plugin Updater has been improved to allow for better compatibility with hosting platforms that use Apache's ModSecurity. In some cases, site owners were seeing a 404 error when attempting to update the Pro version using the Pro Plugin updater because certain ModSecurity rules were blocking the Pro Updater requests. The Pro Plugin Updater now uses WP Transients to store the necessary metadata, which works around the issue with ModSecurity. Props to @seozones for reporting and @jaswsinc for help fixing this. [Issue #416](https://github.com/websharks/comet-cache/issues/416).
17
+ - **Enhancement** (Pro): When Static CDN Filters are enabled, it's now possible to disable the automatic insertion of rules into your `.htaccess` file that are designed to prevent issues with [CORS](https://cometcache.com/kb-article/what-are-cross-origin-request-blocked-errors/). See _Apache Optimizations → Send Access-Control-Allow-Origin Header?_ See [Issue #787](https://github.com/websharks/comet-cache/issues/787).
18
+ - **Enhancement** (Pro): The HTML Notes added to the bottom of a cached page now specify if the page was cached as the result of an HTTP Request or if it was cached by the Auto-Cache Engine. Props @kristineds. See [Issue #292](https://github.com/websharks/comet-cache/issues/292).
19
+ - **Enhancement** (Pro): The Auto-Cache Engine now supports a fallback to cURL using the WP HTTP API. If your PHP configuration has `allow_fopen_url=0`, the Auto-Cache Engine will use the fallback to download the XML Sitemap and parse it from a temporary file. If you want to force the use of this fallback even when `allow_fopen_url=1`, you can use [a filter](https://github.com/websharks/comet-cache/issues/440#issuecomment-228338371). See [Issue #440](https://github.com/websharks/comet-cache/issues/440).
20
+ - **UI Enhancement** (Pro): A second button has been added to the bottom of the Pro Plugin Updater page that allows you to "Save and Update Comet Cache Pro" in one step. Props @renzms. See [Issue #741](https://github.com/websharks/comet-cache/issues/741).
21
+ - **UI Enhancement** (Pro): The "Cache Stats" button in Admin Bar is now linked to the Cache Stats page. Instead of hovering over the button and then clicking "More Info" inside the popup panel, you can now just click the "Cache Stats" button to go directly to the Cache Stats page. Props @Presskopp, @renzms. See [Issue #780](https://github.com/websharks/comet-cache/issues/780).
22
+ - **Comment Mail Compatibility:** Improved compatibility with the Comment Mail plugin by automatically clearing the cache whenever Comment Mail options are changed. Many of the Comment Mail options affect front-end portions of the site, so it's important that the cache is cleared whenever Comment Mail options change. See [Comment Mail Issue #278](https://github.com/websharks/comment-mail/issues/278#issuecomment-225994050).
23
+ - **PHP Compatibility:** Improved compatibility back to PHP 5.2 (the lowest version allowed by WordPress). Comet Cache still requires PHP 5.4+, but if you install Comet Cache on a site running PHP 5.2, it will now fail gracefully with a Dashboard notice indicating PHP 5.4+ is required, instead of producing a fatal error. See [Issue #784](https://github.com/websharks/comet-cache/issues/784).
24
+ - **WP-CLI Compatibility**: Fixed a bug with deactivating Comet Cache using WP-CLI. Doing so was producing a "Invalid argument; host token empty!" error message. This has been resolved. Props @MarioKnight @jaswsinc @renzms. See [Issue #728](https://github.com/websharks/comet-cache/issues/728).
25
+ - Renamed `COMET_CACHE_ALLOW_BROWSER_CACHE` constant to `COMET_CACHE_ALLOW_CLIENT_SIDE_CACHE`. Backwards compatibility has been maintained.
26
+ - Renamed `allow_browser_cache` plugin option to `allow_client_side_cache`.
27
+
28
  = v160521 =
29
 
30
  - **Bug Fix**: Fixed a bug that, in some scenarios, resulted in "PHP Fatal error: Undefined class constant 'CACHE_PATH_NO_PATH_INDEX'". This also affected the Cache Statistics feature (Comet Cache Pro), resulting in a blank panel when hovering over the Cache Stats button in the menu bar. See [Issue #752](https://github.com/websharks/comet-cache/issues/752).
comet-cache.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /*
3
- Version: 160521
4
  Text Domain: comet-cache
5
  Plugin Name: Comet Cache
6
  Network: true
@@ -14,4 +14,4 @@ Description: Comet Cache is an advanced WordPress caching plugin inspired by sim
14
  if (!defined('WPINC')) {
15
  exit('Do NOT access this file directly: '.basename(__FILE__));
16
  }
17
- require_once __DIR__.'/plugin.php';
1
  <?php
2
  /*
3
+ Version: 160706
4
  Text Domain: comet-cache
5
  Plugin Name: Comet Cache
6
  Network: true
14
  if (!defined('WPINC')) {
15
  exit('Do NOT access this file directly: '.basename(__FILE__));
16
  }
17
+ require_once dirname(__FILE__).'/plugin.php';
plugin.php CHANGED
@@ -2,14 +2,15 @@
2
  if (!defined('WPINC')) {
3
  exit('Do NOT access this file directly: '.basename(__FILE__));
4
  }
5
- $GLOBALS['wp_php_rv'] = '5.3.2'; //php-required-version// // Leaving this at v5.3.2 so that we can have more control over Dashboard messages below.
 
6
 
7
- if (require(__DIR__.'/src/vendor/websharks/wp-php-rv/src/includes/check.php')) {
8
  if (!empty($_REQUEST['comet_cache_mbstring_deprecated_warning_bypass']) && is_admin()) {
9
  update_site_option('comet_cache_mbstring_deprecated_warning_bypass', time());
10
  }
11
 
12
- ${__FILE__}['apc_enabled'] = (extension_loaded('apc') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) && filter_var(ini_get('apc.cache_by_default'), FILTER_VALIDATE_BOOLEAN) && stripos((string) ini_get('apc.filters'), 'comet-cache') === false) ? true : false;
13
 
14
  if ((!version_compare(PHP_VERSION, '5.4', '>=') || ${__FILE__}['apc_enabled'])) { // If PHP <= 5.4 or APC is enabled
15
 
@@ -86,7 +87,7 @@ if (require(__DIR__.'/src/vendor/websharks/wp-php-rv/src/includes/check.php')) {
86
  );
87
  }
88
 
89
- require_once __DIR__.'/src/includes/plugin.php';
90
  }
91
  } else {
92
  wp_php_rv_notice('Comet Cache');
2
  if (!defined('WPINC')) {
3
  exit('Do NOT access this file directly: '.basename(__FILE__));
4
  }
5
+ $GLOBALS['wp_php_rv']['rv'] = '5.3.2'; //php-required-version// // Leaving this at v5.3.2 so that we can have more control over Dashboard messages below.
6
+ $GLOBALS['wp_php_rv']['re'] = array('mbstring');
7
 
8
+ if (require(dirname(__FILE__).'/src/vendor/websharks/wp-php-rv/src/includes/check.php')) {
9
  if (!empty($_REQUEST['comet_cache_mbstring_deprecated_warning_bypass']) && is_admin()) {
10
  update_site_option('comet_cache_mbstring_deprecated_warning_bypass', time());
11
  }
12
 
13
+ ${__FILE__}['apc_enabled'] = (extension_loaded('apc') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) && filter_var(ini_get('apc.cache_by_default'), FILTER_VALIDATE_BOOLEAN) && mb_stripos((string) ini_get('apc.filters'), 'comet-cache') === false) ? true : false;
14
 
15
  if ((!version_compare(PHP_VERSION, '5.4', '>=') || ${__FILE__}['apc_enabled'])) { // If PHP <= 5.4 or APC is enabled
16
 
87
  );
88
  }
89
 
90
+ require_once dirname(__FILE__).'/src/includes/plugin.php';
91
  }
92
  } else {
93
  wp_php_rv_notice('Comet Cache');
readme.txt CHANGED
@@ -1,6 +1,6 @@
1
  === Comet Cache ===
2
 
3
- Stable tag: 160521
4
  Requires at least: 4.2
5
  Tested up to: 4.6-alpha
6
  Text Domain: comet-cache
@@ -32,21 +32,31 @@ The Comet Cache plugin uses configuration options that you select from the optio
32
  - Caching for 404 requests to reduce the impact of those requests on the server.
33
  - RSS, RDF, and Atom Feed caching.
34
  - The ability to cache or ignore URLs that contain query strings (GET Requests).
 
 
35
  - An Advanced Cache Plugin system for theme and plugin developers.
36
 
37
  = Pro Features =
38
 
39
  - The ability to cache logged-in users too! (VERY powerful, particularly for membership sites).
40
  - A new improved "Clear Cache" button in the admin bar (along with an option to enable/disable this feature).
 
41
  - The ability to disable Dashboard notifications related to automatic clearing/purging on change detections.
42
  - The ability to clear Markdown-related cache files generated by the s2Clean theme for WordPress (if installed).
43
  - The ability to run custom PHP code whenever the cache is cleared.
 
 
44
  - Cache Statistics to help you gain insight into the status of your site cache.
45
  - Import/Export functionality for Comet Cache configuration files.
46
  - A Dynamic Version Salt (customize the caching engine).
 
47
  - HTML Compressor to automatically combine and compresses CSS/JS/HTML code.
48
  - Auto-Cache Engine to pre-cache your site at 15-minute intervals.
49
  - Static CDN Filters to serve some and/or ALL static files on your site from a CDN of your choosing, including support for Multiple CDN Host Names, Domain Sharding, and WordPress Multisite Networks.
 
 
 
 
50
  - An Automatic Updater to update Comet Cache Pro from your WordPress Dashboard.
51
  - Rockstar support for all Comet Cache features.
52
 
@@ -68,7 +78,7 @@ TIP: you can preview Pro features in the free version by clicking the "Preview P
68
  12. URI Exclusion Patterns
69
  13. HTTP Referrer Exclusion Patterns
70
  14. User-Agent Exclusion Patterns
71
- 15. GZIP Compression
72
  16. Theme/Plugin Developers
73
 
74
  == Installation ==
@@ -120,7 +130,7 @@ Once Comet Cache has been enabled, **you'll need to log out** (and/or clear brow
120
 
121
  **To verify that Comet Cache is working**, navigate your site like a normal visitor would. Right-click on any page (choose View Source), then scroll to the very bottom of the document. At the bottom, you'll find comments that show Comet Cache stats and information. You should also notice that page-to-page navigation is lightning fast compared to what you experienced prior to installing Comet Cache.
122
 
123
- = What is the down side to running Comet Cache? =
124
 
125
  There is NOT one! Comet Cache is a MUST HAVE for every WordPress® powered site. In fact, we really can't think of any site running WordPress® that would want to be without it. To put it another way, the WordPress® software itself comes with a built in action reference for an `advanced-cache.php` file, because WordPress® developers realize the importance of such as plugin. The `/wp-content/advanced-cache.php` file is named as such, because the WordPress® developers expect it to be there when caching is enabled by a plugin. If you don't have the `/wp-content/advanced-cache.php` file yet, it is because you have not enabled Comet Cache from the options panel yet.
126
 
@@ -136,23 +146,6 @@ The cache files are stored in a special directory: `/wp-content/cache/comet-cach
136
 
137
  Whenever a request comes in from someone on the web, Comet Cache checks to see if it can serve a cached file; e.g. it looks at the `HTTPS/HTTP_HOST/REQUEST_URI` environent variables, then it checks the `/comet-cache/cache` directory. If a cache file has been built already, and it matches an existing `HTTPS.HTTP_HOST.REQUEST_URI` combination; and it is not too old (see: **Dashboard -› Comet Cache -› Cache Directory/Expiration Time**), then it will serve that file instead of asking WordPress® to regenerate it. This adds tremendous speed to your site and reduces server load.
138
 
139
- If you have GZIP compression enabled, then the cache file is also sent to the browser with compression (recommended). Modern web browsers that support this technique will definitely take advantage of it. After all, if it is easier to email a zip file, it's also easier to download a web page that way. That is why on-the-fly GZIP compression for web pages is recommended. This is supported by all modern browsers.
140
-
141
- If you want to enable GZIP, create an `.htaccess` file in your WordPress® installation directory and put the following few lines in it. Alternatively, if you already have an `.htaccess` file, just add these lines to it, and that is all there is to it. GZIP is now enabled!
142
-
143
- <IfModule deflate_module>
144
- <IfModule filter_module>
145
- AddOutputFilterByType DEFLATE text/plain text/html
146
- AddOutputFilterByType DEFLATE text/xml application/xml application/xhtml+xml application/xml-dtd
147
- AddOutputFilterByType DEFLATE application/rdf+xml application/rss+xml application/atom+xml image/svg+xml
148
- AddOutputFilterByType DEFLATE text/css text/javascript application/javascript application/x-javascript
149
- AddOutputFilterByType DEFLATE font/otf font/opentype application/font-otf application/x-font-otf
150
- AddOutputFilterByType DEFLATE font/ttf font/truetype application/font-ttf application/x-font-ttf
151
- </IfModule>
152
- </IfModule>
153
-
154
- If your installation of Apache does not have `mod_deflate` installed. You can also enable GZIP compression using PHP configuration alone. In your `php.ini` file, you can simply add the following line anywhere: `zlib.output_compression = on`
155
-
156
  = What happens if a user logs in? Are cache files used then? =
157
 
158
  By default, Comet Cache does NOT serve cached pages to users who are logged in, or to users who have left comments recently. Comet Cache also excludes administrative pages, login pages, POST/PUT/DELETE/GET(w/ query string) requests and/or CLI processes. That being said, the Pro version of Comet Cache DOES make it possible to cache pages even when users ARE logged-in; adding even more speed! This is particularly helpful on membership sites; e.g. sites that run plugins like s2Member™ for instance.
@@ -167,7 +160,7 @@ By default, Comet Cache does NOT serve cached pages to users who are logged in,
167
 
168
  There is no need to use an `.htaccess` file with this plugin; caching is handled by WordPress®/PHP alone. That being said, if you also want to take advantage of GZIP compression (and we do recommend this), then you WILL need an `.htaccess` file to accomplish that part. This plugin fully supports GZIP compression on its output. However, it does not handle GZIP compression directly. We purposely left GZIP compression out of this plugin, because GZIP compression is something that should really be enabled at the Apache level or inside your `php.ini` file. GZIP compression can be used for things like JavaScript and CSS files as well, so why bother turning it on for only WordPress-generated pages when you can enable GZIP at the server level and cover all the bases!
169
 
170
- If you want to enable GZIP, create an `.htaccess` file in your WordPress® installation directory and put the following few lines in it. Alternatively, if you already have an `.htaccess` file, just add these lines to it, and that is all there is to it. GZIP is now enabled!
171
 
172
  <IfModule deflate_module>
173
  <IfModule filter_module>
@@ -240,7 +233,7 @@ WordPress® Multisite Networking is a special consideration in WordPress®. If C
240
 
241
  You don't have to use an `.htaccess` file to enjoy the performance enhancements provided by this plugin; caching is handled by WordPress®/PHP alone. That being said, if you want to take advantage of GZIP compression (and we do recommend this), then you WILL need an `.htaccess` file to accomplish that part. This plugin fully supports GZIP compression on its output. However, it does not handle GZIP compression directly. We purposely left GZIP compression out of this plugin, because GZIP compression is something that should really be enabled at the Apache level or inside your `php.ini` file. GZIP compression can be used for things like JavaScript and CSS files as well, so why bother turning it on for only WordPress-generated pages when you can enable GZIP at the server level and cover all the bases!
242
 
243
- If you want to enable GZIP, create an `.htaccess` file in your WordPress® installation directory and put the following few lines in it. Alternatively, if you already have an `.htaccess` file, just add these lines to it, and that is all there is to it. GZIP is now enabled!
244
 
245
  <IfModule deflate_module>
246
  <IfModule filter_module>
@@ -272,15 +265,23 @@ Comet Cache is now completely uninstalled and you can start fresh :-)
272
 
273
  - The ability to cache logged-in users too! (VERY powerful, particularly for membership sites).
274
  - A new improved "Clear Cache" button in the admin bar (along with an option to enable/disable this feature).
 
275
  - The ability to disable Dashboard notifications related to automatic clearing/purging on change detections.
276
  - The ability to clear Markdown-related cache files generated by the s2Clean theme for WordPress (if installed).
277
  - The ability to run custom PHP code whenever the cache is cleared.
 
 
278
  - Cache Statistics to help you gain insight into the status of your site cache.
279
  - Import/Export functionality for Comet Cache configuration files.
280
  - A Dynamic Version Salt (customize the caching engine).
 
281
  - HTML Compressor to automatically combine and compresses CSS/JS/HTML code.
282
  - Auto-Cache Engine to pre-cache your site at 15-minute intervals.
283
  - Static CDN Filters to serve some and/or ALL static files on your site from a CDN of your choosing, including support for Multiple CDN Host Names, Domain Sharding, and WordPress Multisite Networks.
 
 
 
 
284
  - An Automatic Updater to update Comet Cache Pro from your WordPress Dashboard.
285
  - Rockstar support for all Comet Cache features.
286
 
@@ -291,7 +292,7 @@ Comet Cache is now completely uninstalled and you can start fresh :-)
291
  Comet Cache Pro is a wholly contained plugin that _does not_ require Comet Cache Lite to be installed. To install Comet Cache Pro,
292
 
293
  1. Deactivate and delete Comet Cache Lite, if it is currently installed
294
- 1. Download Comet Cache Pro from your account at WebSharks-Inc.com
295
  1. From your WordPress Dashboard, go to **Dashboard -> Plugins -> Add New** and then click on the **Upload Plugin** button at the top
296
  1. Select the Comet Cache Pro zip file you downloaded in step 2 and click "Install Now"
297
  1. After the plugin finishes installing, click the "Activate Plugin" link
@@ -309,7 +310,7 @@ In addition to the [WordPress Requirements](http://wordpress.org/about/requireme
309
 
310
  == License ==
311
 
312
- Copyright: © 2013 [WebSharks, Inc.](http://www.websharks-inc.com/bizdev/) (coded in the USA)
313
 
314
  Released under the terms of the [GNU General Public License](http://www.gnu.org/licenses/gpl-2.0.html).
315
 
@@ -336,6 +337,33 @@ Requires WordPress v4.2+.
336
 
337
  == Changelog ==
338
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
339
  = v160521 =
340
 
341
  - **Bug Fix**: Fixed a bug that, in some scenarios, resulted in "PHP Fatal error: Undefined class constant 'CACHE_PATH_NO_PATH_INDEX'". This also affected the Cache Statistics feature (Comet Cache Pro), resulting in a blank panel when hovering over the Cache Stats button in the menu bar. See [Issue #752](https://github.com/websharks/comet-cache/issues/752).
@@ -366,24 +394,4 @@ Requires WordPress v4.2+.
366
  - **Compatibility: WP-CLI.** When installing Comet Cache via WP-CLI, Comet Cache is now automatically enabled. There's no need to manually enable Comet Cache from within the plugin options after installing. Props @jaswsinc. See [Issue #464](https://github.com/websharks/comet-cache/issues/464).
367
  - **Required WordPress Version is now v4.2.** The minimum required WordPress version has been bumped from v4.1 to v4.2. See [Issue #706](https://github.com/websharks/comet-cache/issues/706).
368
 
369
- = v160227 =
370
-
371
- - **Bug Fix**: Fixed a ZenCache Backwards Compatibility bug that was preventing calls to `$GLOBALS['zencache']` from working properly with Comet Cache. See [Issue #689](https://github.com/websharks/comet-cache/issues/689)
372
- - **Bug Fix**: Fixed a ZenCache Backwards Compatibility bug that was preventing `ZENCACHE_ALLOWED` from working properly with Comet Cache. See [Issue #683](https://github.com/websharks/comet-cache/issues/683).
373
- - **Bug Fix**: Fixed a Quick Cache Backwards Compatibility bug that was preventing calls to `$GLOBALS['quick_cache']` from working properly with Comet Cache. Props to @Kedakai for reporting. See [Issue #691](https://github.com/websharks/comet-cache/issues/691).
374
- - **Bug Fix** (Pro): Fixed an Auto-Cache Engine bug that was preventing the Auto-Cache Engine from generating cached pages. Props @digitalhexcode for reporting. See [Issue #679](https://github.com/websharks/comet-cache/issues/679).
375
- - **Enhancement**: Improved the way Comet Cache handles file locking in an effort to improve compatibility with various environments. There were reports of issues with PHP FPM/FastCGI and this release attempts to address those. See [Issue #671](https://github.com/websharks/comet-cache/issues/671)
376
- - **Enhancement** (Pro): A new HTML Compression option allows you to define whether or not HTML Compression should be enabled for Logged-In users (when Logged-In User caching is enabled). See **Comet Cache → Plugin Options → HTML Compression → Enable HTML Compression for Logged-In Users?**. Props @renzms. See [Issue #650](https://github.com/websharks/comet-cache/issues/650).
377
- - **Accelerated Mobile Pages (AMP) Compatibility**: Added full support for Accelerated Mobile Pages via the [AMP plugin](https://wordpress.org/plugins/amp/). Comet Cache now works great alongside the AMP plugin. AMP-generated pages will be cached and those cache files will be intelligently cleared when necessary to keep things up-to-date. See [Issue #688](https://github.com/websharks/comet-cache/issues/688).
378
-
379
- = v160223.1 =
380
-
381
- - **Bug Fix**: Fixes PHP Fatal Error when upgrading from Comet Cache v160211.
382
-
383
- = v160223 =
384
-
385
- - **Announcement: After March 1st, 2016 Comet Cache will require PHP Multibyte String support.** The `mbstring` extension provides Multibyte String support to PHP and is required to properly handle UTF-8 characters, which many sites now use. Without Multibyte String support, caching will be unstable. For that reason we are requiring the `mbstring` extension to improve reliability when caching and to prevent your site from experiencing unforeseen issues in the future..
386
- - **Bug Fix (Multisite)**: Fixed a bug where when Comet Cache was Network Activated the plugin settings link would show up in the plugins list for the Main Site and would lead to a 404 error. The settings link is now only shown when viewing the plugins list from the Network Admin. Props @jaswsinc. See [Issue #675](https://github.com/websharks/zencache/issues/675).
387
- - **Enhancement**: Added support-related links to the plugin options page. Props @renzms. See [Issue #612](https://github.com/websharks/zencache/issues/612#issuecomment-186827661).
388
-
389
  For older changelog history going back to 2009, please see [CHANGELOG.md](https://github.com/websharks/comet-cache/blob/master/CHANGELOG.md).
1
  === Comet Cache ===
2
 
3
+ Stable tag: 160706
4
  Requires at least: 4.2
5
  Tested up to: 4.6-alpha
6
  Text Domain: comet-cache
32
  - Caching for 404 requests to reduce the impact of those requests on the server.
33
  - RSS, RDF, and Atom Feed caching.
34
  - The ability to cache or ignore URLs that contain query strings (GET Requests).
35
+ - Apache Optimizations to enable GZIP Compression.
36
+ - WP-CLI Compatibility.
37
  - An Advanced Cache Plugin system for theme and plugin developers.
38
 
39
  = Pro Features =
40
 
41
  - The ability to cache logged-in users too! (VERY powerful, particularly for membership sites).
42
  - A new improved "Clear Cache" button in the admin bar (along with an option to enable/disable this feature).
43
+ - Options for Automatic and Intelligent Cache Clearing of Posts, Pages, Custom Post Types, Categories, Tags, Links, Themes, Users, and more.
44
  - The ability to disable Dashboard notifications related to automatic clearing/purging on change detections.
45
  - The ability to clear Markdown-related cache files generated by the s2Clean theme for WordPress (if installed).
46
  - The ability to run custom PHP code whenever the cache is cleared.
47
+ - The ability to Auto-Clear a List of Custom URLs.
48
+ - Clear Cache User Permissions to give other users permission to clear the cache by specifying a list of Roles and/or Capabilities.
49
  - Cache Statistics to help you gain insight into the status of your site cache.
50
  - Import/Export functionality for Comet Cache configuration files.
51
  - A Dynamic Version Salt (customize the caching engine).
52
+ - Multisite Host Exclusion Patterns to exclude specific child blogs from being cached in a Multisite Network.
53
  - HTML Compressor to automatically combine and compresses CSS/JS/HTML code.
54
  - Auto-Cache Engine to pre-cache your site at 15-minute intervals.
55
  - Static CDN Filters to serve some and/or ALL static files on your site from a CDN of your choosing, including support for Multiple CDN Host Names, Domain Sharding, and WordPress Multisite Networks.
56
+ - Domain Sharding / Multiple CDN Hosts to work around concurrency limits and make it possible for browsers to download more resources simultaneously.
57
+ - Server Load Monitoring to avoid regenerating the cache while the server is very busy by specifying a maximum server load average.
58
+ - Cache Statistics and Charts to analyze statistics about the page cache, HTML Compressor cache, PHP OPCache, and server health.
59
+ - Apache Optimizations to enable web server GZIP Compression, Leverage Browser Caching, Enforce Canonical URLs, and more.
60
  - An Automatic Updater to update Comet Cache Pro from your WordPress Dashboard.
61
  - Rockstar support for all Comet Cache features.
62
 
78
  12. URI Exclusion Patterns
79
  13. HTTP Referrer Exclusion Patterns
80
  14. User-Agent Exclusion Patterns
81
+ 15. Apache Optimizations
82
  16. Theme/Plugin Developers
83
 
84
  == Installation ==
130
 
131
  **To verify that Comet Cache is working**, navigate your site like a normal visitor would. Right-click on any page (choose View Source), then scroll to the very bottom of the document. At the bottom, you'll find comments that show Comet Cache stats and information. You should also notice that page-to-page navigation is lightning fast compared to what you experienced prior to installing Comet Cache.
132
 
133
+ = What is the downside to running Comet Cache? =
134
 
135
  There is NOT one! Comet Cache is a MUST HAVE for every WordPress® powered site. In fact, we really can't think of any site running WordPress® that would want to be without it. To put it another way, the WordPress® software itself comes with a built in action reference for an `advanced-cache.php` file, because WordPress® developers realize the importance of such as plugin. The `/wp-content/advanced-cache.php` file is named as such, because the WordPress® developers expect it to be there when caching is enabled by a plugin. If you don't have the `/wp-content/advanced-cache.php` file yet, it is because you have not enabled Comet Cache from the options panel yet.
136
 
146
 
147
  Whenever a request comes in from someone on the web, Comet Cache checks to see if it can serve a cached file; e.g. it looks at the `HTTPS/HTTP_HOST/REQUEST_URI` environent variables, then it checks the `/comet-cache/cache` directory. If a cache file has been built already, and it matches an existing `HTTPS.HTTP_HOST.REQUEST_URI` combination; and it is not too old (see: **Dashboard -› Comet Cache -› Cache Directory/Expiration Time**), then it will serve that file instead of asking WordPress® to regenerate it. This adds tremendous speed to your site and reduces server load.
148
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
149
  = What happens if a user logs in? Are cache files used then? =
150
 
151
  By default, Comet Cache does NOT serve cached pages to users who are logged in, or to users who have left comments recently. Comet Cache also excludes administrative pages, login pages, POST/PUT/DELETE/GET(w/ query string) requests and/or CLI processes. That being said, the Pro version of Comet Cache DOES make it possible to cache pages even when users ARE logged-in; adding even more speed! This is particularly helpful on membership sites; e.g. sites that run plugins like s2Member™ for instance.
160
 
161
  There is no need to use an `.htaccess` file with this plugin; caching is handled by WordPress®/PHP alone. That being said, if you also want to take advantage of GZIP compression (and we do recommend this), then you WILL need an `.htaccess` file to accomplish that part. This plugin fully supports GZIP compression on its output. However, it does not handle GZIP compression directly. We purposely left GZIP compression out of this plugin, because GZIP compression is something that should really be enabled at the Apache level or inside your `php.ini` file. GZIP compression can be used for things like JavaScript and CSS files as well, so why bother turning it on for only WordPress-generated pages when you can enable GZIP at the server level and cover all the bases!
162
 
163
+ If you want to enable GZIP and your site is running on the Apache web server, visit **Dashboard -> Comet Cache -> Apache Optimizations -> Enable GZIP Compression?**; or to enable GZIP compression manually create an `.htaccess` file in your WordPress® installation directory (or edit the one that's already there) and put the following few lines in it. That is all there is to it. GZIP is now enabled!
164
 
165
  <IfModule deflate_module>
166
  <IfModule filter_module>
233
 
234
  You don't have to use an `.htaccess` file to enjoy the performance enhancements provided by this plugin; caching is handled by WordPress®/PHP alone. That being said, if you want to take advantage of GZIP compression (and we do recommend this), then you WILL need an `.htaccess` file to accomplish that part. This plugin fully supports GZIP compression on its output. However, it does not handle GZIP compression directly. We purposely left GZIP compression out of this plugin, because GZIP compression is something that should really be enabled at the Apache level or inside your `php.ini` file. GZIP compression can be used for things like JavaScript and CSS files as well, so why bother turning it on for only WordPress-generated pages when you can enable GZIP at the server level and cover all the bases!
235
 
236
+ If you want to enable GZIP and your site is running on the Apache web server, visit **Dashboard -> Comet Cache -> Apache Optimizations -> Enable GZIP Compression?**; or to enable GZIP compression manually create an `.htaccess` file in your WordPress® installation directory (or edit the one that's already there) and put the following few lines in it. That is all there is to it. GZIP is now enabled!
237
 
238
  <IfModule deflate_module>
239
  <IfModule filter_module>
265
 
266
  - The ability to cache logged-in users too! (VERY powerful, particularly for membership sites).
267
  - A new improved "Clear Cache" button in the admin bar (along with an option to enable/disable this feature).
268
+ - Options for Automatic and Intelligent Cache Clearing of Posts, Pages, Custom Post Types, Categories, Tags, Links, Themes, Users, and more.
269
  - The ability to disable Dashboard notifications related to automatic clearing/purging on change detections.
270
  - The ability to clear Markdown-related cache files generated by the s2Clean theme for WordPress (if installed).
271
  - The ability to run custom PHP code whenever the cache is cleared.
272
+ - The ability to Auto-Clear a List of Custom URLs.
273
+ - Clear Cache User Permissions to give other users permission to clear the cache by specifying a list of Roles and/or Capabilities.
274
  - Cache Statistics to help you gain insight into the status of your site cache.
275
  - Import/Export functionality for Comet Cache configuration files.
276
  - A Dynamic Version Salt (customize the caching engine).
277
+ - Multisite Host Exclusion Patterns to exclude specific child blogs from being cached in a Multisite Network.
278
  - HTML Compressor to automatically combine and compresses CSS/JS/HTML code.
279
  - Auto-Cache Engine to pre-cache your site at 15-minute intervals.
280
  - Static CDN Filters to serve some and/or ALL static files on your site from a CDN of your choosing, including support for Multiple CDN Host Names, Domain Sharding, and WordPress Multisite Networks.
281
+ - Domain Sharding / Multiple CDN Hosts to work around concurrency limits and make it possible for browsers to download more resources simultaneously.
282
+ - Server Load Monitoring to avoid regenerating the cache while the server is very busy by specifying a maximum server load average.
283
+ - Cache Statistics and Charts to analyze statistics about the page cache, HTML Compressor cache, PHP OPCache, and server health.
284
+ - Apache Optimizations to enable web server GZIP Compression, Leverage Browser Caching, Enforce Canonical URLs, and more.
285
  - An Automatic Updater to update Comet Cache Pro from your WordPress Dashboard.
286
  - Rockstar support for all Comet Cache features.
287
 
292
  Comet Cache Pro is a wholly contained plugin that _does not_ require Comet Cache Lite to be installed. To install Comet Cache Pro,
293
 
294
  1. Deactivate and delete Comet Cache Lite, if it is currently installed
295
+ 1. Download Comet Cache Pro from your account at CometCache.com
296
  1. From your WordPress Dashboard, go to **Dashboard -> Plugins -> Add New** and then click on the **Upload Plugin** button at the top
297
  1. Select the Comet Cache Pro zip file you downloaded in step 2 and click "Install Now"
298
  1. After the plugin finishes installing, click the "Activate Plugin" link
310
 
311
  == License ==
312
 
313
+ Copyright: © 2016 [WebSharks, Inc.](http://www.websharks-inc.com/bizdev/) (coded in the USA)
314
 
315
  Released under the terms of the [GNU General Public License](http://www.gnu.org/licenses/gpl-2.0.html).
316
 
337
 
338
  == Changelog ==
339
 
340
+ = v160706 =
341
+
342
+ - **New Feature! Apache Optimizations.** This release includes a completely new option panel for Apache Performance Tuning. Current options for Apache tuning include GZIP Compression, Leverage Browser Caching, Enforce Canonical URLs, and Send Access-Control-Allow-Origin Header (for Static CDN Filters). These options automatically add or remove from your `.htaccess` file the appropriate configuration based on the options you enable or disable (all options are disabled by default, so your `.htaccess` file is not modified unless you say so). If you prefer to update your `.htaccess` file manually, the necessary configuration can be viewed beneath each option. Props @jaswsinc, @renzms. See [Issue #789](https://github.com/websharks/comet-cache/issues/789).
343
+ - **New Feature!** A new "Enable GZIP Compression" option has been added to the new Apache Optimizations panel. This option will automatically add the appropriate configuration to your `.htaccess` file to enable GZIP compression. This option is disabled by default. The old "GZIP Compression" panel has been removed in favor of the new option inside Apache Optimizations. Props @renzms, @jaswsinc. See [Issue #764](https://github.com/websharks/comet-cache/issues/764).
344
+ - **New Feature!** Multisite Host Exclusion Patterns. It's now possible to exclude entire sites from the cache in a Multisite Network environment. Domain mapping is also supported! See _Comet Cache → Plugin Options → Host Exclusion Patterns_. If you're running a Multisite Network with Sub-Directories, you can exclude sites using the existing URI Exclusion Patterns feature. Props @kristineds. See [Issue #754](https://github.com/websharks/comet-cache/issues/754).
345
+ - **New Feature (Pro)!** A new "Leverage Browser Caching" option has been added to the new Apache Optimizations panel. This option will automatically add the appropriate configuration to your `.htaccess` file to enable Browser Caching. This option is disabled by default. Props @renzms, @jaswsinc. See [Issue #764](https://github.com/websharks/comet-cache/issues/764).
346
+ - **New Feature (Pro)!** A new "Enforce Canonical URLs" option has been added to the new Apache Optimizations panel. This options adds the appropriate `.htaccess` code to enforce the correct canonical URLs according to your WordPress Permalink settings (Comet Cache detects if the Permalink Structure ends with a trailing slash, or without a trailing slash). Props @renzms, @jaswsinc. See [Issue #554](https://github.com/websharks/comet-cache/issues/554).
347
+ - **Bug Fix**: In some scenarios the Cron Event that cleans up expired cache files (`_cron_comet_cache_cleanup`) would never run, or the Next Run time would constantly reset to 1 minute away from running every time a page was reloaded. We suspect this is a race condition and in attempt to work around this issue we now skip all of our Cron-related checks if Cron is currently in the middle of running a process. Props @xberg and @lkraav for help reporting. See [Issue #653](https://github.com/websharks/comet-cache/issues/653).
348
+ - **Bug Fix**: If your site uses aliased domains, Comet Cache now properly considers all possible domain variations when it clears the cache on WP Standard installations. Props @kristineds, @jaswsinc, @yoffe, and @VR51. See [Issue #608](https://github.com/websharks/comet-cache/issues/608).
349
+ - **Bug Fix** (Pro): Fixed a bug where Comet Cache would appear to prevent WordPress from redirecting Permalinks that don't include a trailing slash, to the URL that does include a trailing slash. This was due to the fact that Comet Cache loads very early on (for caching purposes) and as a result the WordPress `redirect_canonical()` function never gets run. This was fixed by adding an option to the new Apache Optimizations panel that allows you to Enforce Canonical URLs. Props @renzms, @jaswsinc. See [Issue #554](https://github.com/websharks/comet-cache/issues/554).
350
+ - **UX Bug Fix** (Pro): If you had your WordPress Dashboard login details saved by your browser, the browser autofill would automatically fill in the Pro Plugin Updater fields with those details, which then needed to be replaced with your actual Pro license details. The browser autofill has been disabled for those fields (tested in Chrome, Firefox, and Safari). Props @renzms. See [Issue #741](https://github.com/websharks/comet-cache/issues/741).
351
+ - **Enhancement**: Added links the Options Page for the Comet Cache [Twitter](http://twitter.com/cometcache) and [Facebook](http://facebook.com/cometcache) accounts. Props @renzms. [Issue #771](https://github.com/websharks/comet-cache/issues/771).
352
+ - **Enhancement:** Added full support for UTF-8 (multibyte strings). This release adds full support for UTF-8 throughout the Comet Cache codebase, greatly enhancing Comet Cache's ability to deal with file paths and URLs that may contain UTF-8 characters. Props @jaswsinc. [Issue #703](https://github.com/websharks/comet-cache/issues/703).
353
+ - **UI Enhancements**: Improved the Logged-In Users and the Client-Side Caching options panels to dim additional options when the feature is disabled. Additionally, the "Enable HTML Compression for Logged-In Users?" option has been relocated from the HTML Compressor option panel to the more appropriate Logged-In Users option panel. See [Issue #768](https://github.com/websharks/comet-cache/issues/768).
354
+ - **UX Enhancement**: Improved the inline docs for Auto-Clear List of Custom URLs to clarify that full URLs must be provided. Props @renzms. See [Issue #781](https://github.com/websharks/comet-cache/issues/781).
355
+ - **Enhancement** (Pro): The Pro Plugin Updater has been improved to allow for better compatibility with hosting platforms that use Apache's ModSecurity. In some cases, site owners were seeing a 404 error when attempting to update the Pro version using the Pro Plugin updater because certain ModSecurity rules were blocking the Pro Updater requests. The Pro Plugin Updater now uses WP Transients to store the necessary metadata, which works around the issue with ModSecurity. Props to @seozones for reporting and @jaswsinc for help fixing this. [Issue #416](https://github.com/websharks/comet-cache/issues/416).
356
+ - **Enhancement** (Pro): When Static CDN Filters are enabled, it's now possible to disable the automatic insertion of rules into your `.htaccess` file that are designed to prevent issues with [CORS](https://cometcache.com/kb-article/what-are-cross-origin-request-blocked-errors/). See _Apache Optimizations → Send Access-Control-Allow-Origin Header?_ See [Issue #787](https://github.com/websharks/comet-cache/issues/787).
357
+ - **Enhancement** (Pro): The HTML Notes added to the bottom of a cached page now specify if the page was cached as the result of an HTTP Request or if it was cached by the Auto-Cache Engine. Props @kristineds. See [Issue #292](https://github.com/websharks/comet-cache/issues/292).
358
+ - **Enhancement** (Pro): The Auto-Cache Engine now supports a fallback to cURL using the WP HTTP API. If your PHP configuration has `allow_fopen_url=0`, the Auto-Cache Engine will use the fallback to download the XML Sitemap and parse it from a temporary file. If you want to force the use of this fallback even when `allow_fopen_url=1`, you can use [a filter](https://github.com/websharks/comet-cache/issues/440#issuecomment-228338371). See [Issue #440](https://github.com/websharks/comet-cache/issues/440).
359
+ - **UI Enhancement** (Pro): A second button has been added to the bottom of the Pro Plugin Updater page that allows you to "Save and Update Comet Cache Pro" in one step. Props @renzms. See [Issue #741](https://github.com/websharks/comet-cache/issues/741).
360
+ - **UI Enhancement** (Pro): The "Cache Stats" button in Admin Bar is now linked to the Cache Stats page. Instead of hovering over the button and then clicking "More Info" inside the popup panel, you can now just click the "Cache Stats" button to go directly to the Cache Stats page. Props @Presskopp, @renzms. See [Issue #780](https://github.com/websharks/comet-cache/issues/780).
361
+ - **Comment Mail Compatibility:** Improved compatibility with the Comment Mail plugin by automatically clearing the cache whenever Comment Mail options are changed. Many of the Comment Mail options affect front-end portions of the site, so it's important that the cache is cleared whenever Comment Mail options change. See [Comment Mail Issue #278](https://github.com/websharks/comment-mail/issues/278#issuecomment-225994050).
362
+ - **PHP Compatibility:** Improved compatibility back to PHP 5.2 (the lowest version allowed by WordPress). Comet Cache still requires PHP 5.4+, but if you install Comet Cache on a site running PHP 5.2, it will now fail gracefully with a Dashboard notice indicating PHP 5.4+ is required, instead of producing a fatal error. See [Issue #784](https://github.com/websharks/comet-cache/issues/784).
363
+ - **WP-CLI Compatibility**: Fixed a bug with deactivating Comet Cache using WP-CLI. Doing so was producing a "Invalid argument; host token empty!" error message. This has been resolved. Props @MarioKnight @jaswsinc @renzms. See [Issue #728](https://github.com/websharks/comet-cache/issues/728).
364
+ - Renamed `COMET_CACHE_ALLOW_BROWSER_CACHE` constant to `COMET_CACHE_ALLOW_CLIENT_SIDE_CACHE`. Backwards compatibility has been maintained.
365
+ - Renamed `allow_browser_cache` plugin option to `allow_client_side_cache`.
366
+
367
  = v160521 =
368
 
369
  - **Bug Fix**: Fixed a bug that, in some scenarios, resulted in "PHP Fatal error: Undefined class constant 'CACHE_PATH_NO_PATH_INDEX'". This also affected the Cache Statistics feature (Comet Cache Pro), resulting in a blank panel when hovering over the Cache Stats button in the menu bar. See [Issue #752](https://github.com/websharks/comet-cache/issues/752).
394
  - **Compatibility: WP-CLI.** When installing Comet Cache via WP-CLI, Comet Cache is now automatically enabled. There's no need to manually enable Comet Cache from within the plugin options after installing. Props @jaswsinc. See [Issue #464](https://github.com/websharks/comet-cache/issues/464).
395
  - **Required WordPress Version is now v4.2.** The minimum required WordPress version has been bumped from v4.1 to v4.2. See [Issue #706](https://github.com/websharks/comet-cache/issues/706).
396
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
397
  For older changelog history going back to 2009, please see [CHANGELOG.md](https://github.com/websharks/comet-cache/blob/master/CHANGELOG.md).
src/client-s/css/menu-pages.min.css CHANGED
@@ -1,2 +1,2 @@
1
- @font-face{font-family:sharkicons;src:url("../../vendor/websharks/sharkicons/src/fonts/sharkicons.eot?v160221");src:url("../../vendor/websharks/sharkicons/src/fonts/sharkicons.eot?#iefix&v160221") format("embedded-opentype"),url("../../vendor/websharks/sharkicons/src/fonts/sharkicons.ttf?v160221") format("truetype"),url("../../vendor/websharks/sharkicons/src/fonts/sharkicons.woff?v160221") format("woff"),url("../../vendor/websharks/sharkicons/src/fonts/sharkicons.svg?v160221#sharkicons") format("svg");font-weight:normal;font-style:normal}.si::before{font:normal normal normal 14px/1 sharkicons;text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased;font-smoothing:antialiased;display:inline-block;font-size:inherit;text-decoration:inherit;text-transform:none}.si-broom::before{content:""}.si-comment-mail-one::before{content:""}.si-comment-mail::before{content:""}.si-s2member::before{content:""}.si-websharks::before{content:""}.si-wp-kb-articles::before{content:""}.si-zencache-logo::before{content:""}.si-zencache::before{content:""}.si-wp-sharks::before{content:""}.si-wp-sharks-fin::before{content:""}.si-comet-cache::before{content:""}.si-comet-cache-logo::before{content:""}.si-comet-cache-comet::before{content:""}.si-feat-watch::before{content:""}.si-feat-server::before{content:""}.si-feat-layers::before{content:""}.si-feat-box::before{content:""}.si-feat-ellipsis::before{content:""}.si-typi-group::before{content:""}.si-enty-bookmark::before{content:""}.si-enty-bookmarks::before{content:""}.si-enty-open-book::before{content:""}.si-enty-archive::before{content:""}.si-enty-area-graph::before{content:""}.si-enty-bucket::before{content:""}.si-enty-colors::before{content:""}.si-enty-copy::before{content:""}.si-enty-drive::before{content:""}.si-enty-feather::before{content:""}.si-enty-gauge::before{content:""}.si-enty-hand::before{content:""}.si-enty-lab-flask::before{content:""}.si-enty-mask::before{content:""}.si-enty-medal::before{content:""}.si-enty-exclamation::before{content:""}.si-enty-palette::before{content:""}.si-enty-ruler::before{content:""}.si-enty-shop::before{content:""}.si-enty-basket::before{content:""}.si-enty-cart::before{content:""}.si-enty-traffic-cone::before{content:""}.si-enty-tree::before{content:""}.si-enty-trophy::before{content:""}.si-enty-v-card::before{content:""}.si-enty-google-hangouts::before{content:""}.si-eleg-line-graph::before{content:""}.si-eleg-male::before{content:""}.si-eleg-female::before{content:""}.si-eleg-atom::before{content:""}.si-broc-cart::before{content:""}.si-broc-crap::before{content:""}.si-broc-atom::before{content:""}.si-icom-headphones::before{content:""}.si-icom-barcode::before{content:""}.si-icom-user::before{content:""}.si-icom-users::before{content:""}.si-icom-user-plus::before{content:""}.si-icom-user-minus::before{content:""}.si-icom-user-check::before{content:""}.si-icom-user-tie::before{content:""}.si-icom-key::before{content:""}.si-icom-key2::before{content:""}.si-icom-happy::before{content:""}.si-icom-happy2::before{content:""}.si-icom-smile::before{content:""}.si-icom-smile2::before{content:""}.si-icom-tongue::before{content:""}.si-icom-tongue2::before{content:""}.si-icom-sad::before{content:""}.si-icom-sad2::before{content:""}.si-icom-wink::before{content:""}.si-icom-wink2::before{content:""}.si-icom-grin::before{content:""}.si-icom-grin2::before{content:""}.si-icom-cool::before{content:""}.si-icom-cool2::before{content:""}.si-icom-angry::before{content:""}.si-icom-angry2::before{content:""}.si-icom-evil::before{content:""}.si-icom-evil2::before{content:""}.si-icom-shocked::before{content:""}.si-icom-shocked2::before{content:""}.si-icom-baffled::before{content:""}.si-icom-baffled2::before{content:""}.si-icom-confused::before{content:""}.si-icom-confused2::before{content:""}.si-icom-neutral::before{content:""}.si-icom-neutral2::before{content:""}.si-icom-hipster::before{content:""}.si-icom-hipster2::before{content:""}.si-icom-wondering::before{content:""}.si-icom-wondering2::before{content:""}.si-icom-sleepy::before{content:""}.si-icom-sleepy2::before{content:""}.si-icom-frustrated::before{content:""}.si-icom-frustrated2::before{content:""}.si-icom-crying::before{content:""}.si-icom-crying2::before{content:""}.si-icom-spell-check::before{content:""}.si-icom-command-key::before{content:""}.si-icom-shift-key::before{content:""}.si-icom-control-key::before{content:""}.si-icom-option-key::before{content:""}.si-icom-wordpress::before{content:""}.si-icom-wordpress-square::before{content:""}.si-icom-yahoo::before{content:""}.si-icom-linux::before{content:""}.si-icom-finder::before{content:""}.si-icom-android::before{content:""}.si-icom-reddit::before{content:""}.si-icom-paypal::before{content:""}.si-icom-git::before{content:""}.si-octi-alignment-align::before{content:""}.si-octi-alignment-aligned-to::before{content:""}.si-octi-alignment-unalign::before{content:""}.si-octi-bookmark::before{content:""}.si-octi-broadcast::before{content:""}.si-octi-browser::before{content:""}.si-octi-checklist::before{content:""}.si-octi-circuit-board::before{content:""}.si-octi-clippy::before{content:""}.si-octi-cloud-download::before{content:""}.si-octi-cloud-upload::before{content:""}.si-octi-comment::before{content:""}.si-octi-comments::before{content:""}.si-octi-tach::before{content:""}.si-octi-device-camera::before{content:""}.si-octi-device-camera-video::before{content:""}.si-octi-device-desktop::before{content:""}.si-octi-diff::before{content:""}.si-octi-file-binary::before{content:""}.si-octi-file-media::before{content:""}.si-octi-file-submodule::before{content:""}.si-octi-file-symlink-directory::before{content:""}.si-octi-file-symlink-file::before{content:""}.si-octi-fold::before{content:""}.si-octi-git-branch::before{content:""}.si-octi-git-commit::before{content:""}.si-octi-git-compare::before{content:""}.si-octi-git-merge::before{content:""}.si-octi-git-pull-request::before{content:""}.si-octi-graph::before{content:""}.si-octi-home::before{content:""}.si-octi-horizontal-rule::before{content:""}.si-octi-key::before{content:""}.si-octi-light-bulb::before{content:""}.si-octi-link-external::before{content:""}.si-octi-lock::before{content:""}.si-octi-markdown::before{content:""}.si-octi-microscope::before{content:""}.si-octi-mirror::before{content:""}.si-octi-move-down::before{content:""}.si-octi-move-left::before{content:""}.si-octi-move-right::before{content:""}.si-octi-move-up::before{content:""}.si-octi-mute::before{content:""}.si-octi-organization::before{content:""}.si-octi-package::before{content:""}.si-octi-paintcan::before{content:""}.si-octi-person::before{content:""}.si-octi-plug::before{content:""}.si-octi-podium::before{content:""}.si-octi-pulse::before{content:""}.si-octi-puzzle::before{content:""}.si-octi-repo::before{content:""}.si-octi-repo-clone::before{content:""}.si-octi-repo-force-push::before{content:""}.si-octi-repo-forked::before{content:""}.si-octi-repo-pull::before{content:""}.si-octi-repo-push::before{content:""}.si-octi-rocket::before{content:""}.si-octi-ruby::before{content:""}.si-octi-screen-full::before{content:""}.si-octi-screen-normal::before{content:""}.si-octi-sign-in::before{content:""}.si-octi-sign-out::before{content:""}.si-octi-split::before{content:""}.si-octi-squirrel::before{content:""}.si-octi-steps::before{content:""}.si-octi-tag::before{content:""}.si-octi-telescope::before{content:""}.si-octi-terminal::before{content:""}.si-octi-unfold::before{content:""}.si-octi-versions::before{content:""}.si-glass::before{content:""}.si-music::before{content:""}.si-search::before{content:""}.si-envelope-o::before{content:""}.si-heart::before{content:""}.si-star::before{content:""}.si-star-o::before{content:""}.si-user::before{content:""}.si-film::before{content:""}.si-th-large::before{content:""}.si-th::before{content:""}.si-th-list::before{content:""}.si-check::before{content:""}.si-close::before{content:""}.si-search-plus::before{content:""}.si-search-minus::before{content:""}.si-power-off::before{content:""}.si-signal::before{content:""}.si-cog::before{content:""}.si-trash-o::before{content:""}.si-home::before{content:""}.si-file-o::before{content:""}.si-clock-o::before{content:""}.si-road::before{content:""}.si-download::before{content:""}.si-arrow-circle-o-down::before{content:""}.si-arrow-circle-o-up::before{content:""}.si-inbox::before{content:""}.si-play-circle-o::before{content:""}.si-repeat::before{content:""}.si-refresh::before{content:""}.si-list-alt::before{content:""}.si-lock::before{content:""}.si-flag::before{content:""}.si-headphones::before{content:""}.si-volume-off::before{content:""}.si-volume-down::before{content:""}.si-volume-up::before{content:""}.si-qrcode::before{content:""}.si-barcode::before{content:""}.si-tag::before{content:""}.si-tags::before{content:""}.si-book::before{content:""}.si-bookmark::before{content:""}.si-print::before{content:""}.si-camera::before{content:""}.si-font::before{content:""}.si-bold::before{content:""}.si-italic::before{content:""}.si-text-height::before{content:""}.si-text-width::before{content:""}.si-align-left::before{content:""}.si-align-center::before{content:""}.si-align-right::before{content:""}.si-align-justify::before{content:""}.si-list::before{content:""}.si-dedent::before{content:""}.si-indent::before{content:""}.si-video-camera::before{content:""}.si-image::before{content:""}.si-pencil::before{content:""}.si-map-marker::before{content:""}.si-adjust::before{content:""}.si-tint::before{content:""}.si-edit::before{content:""}.si-share-square-o::before{content:""}.si-check-square-o::before{content:""}.si-arrows::before{content:""}.si-step-backward::before{content:""}.si-fast-backward::before{content:""}.si-backward::before{content:""}.si-play::before{content:""}.si-pause::before{content:""}.si-stop::before{content:""}.si-forward::before{content:""}.si-fast-forward::before{content:""}.si-step-forward::before{content:""}.si-eject::before{content:""}.si-chevron-left::before{content:""}.si-chevron-right::before{content:""}.si-plus-circle::before{content:""}.si-minus-circle::before{content:""}.si-times-circle::before{content:""}.si-check-circle::before{content:""}.si-question-circle::before{content:""}.si-info-circle::before{content:""}.si-crosshairs::before{content:""}.si-times-circle-o::before{content:""}.si-check-circle-o::before{content:""}.si-ban::before{content:""}.si-arrow-left::before{content:""}.si-arrow-right::before{content:""}.si-arrow-up::before{content:""}.si-arrow-down::before{content:""}.si-mail-forward::before{content:""}.si-expand::before{content:""}.si-compress::before{content:""}.si-plus::before{content:""}.si-minus::before{content:""}.si-asterisk::before{content:""}.si-exclamation-circle::before{content:""}.si-gift::before{content:""}.si-leaf::before{content:""}.si-fire::before{content:""}.si-eye::before{content:""}.si-eye-slash::before{content:""}.si-exclamation-triangle::before{content:""}.si-plane::before{content:""}.si-calendar::before{content:""}.si-random::before{content:""}.si-comment::before{content:""}.si-magnet::before{content:""}.si-chevron-up::before{content:""}.si-chevron-down::before{content:""}.si-retweet::before{content:""}.si-shopping-cart::before{content:""}.si-folder::before{content:""}.si-folder-open::before{content:""}.si-arrows-v::before{content:""}.si-arrows-h::before{content:""}.si-bar-chart::before{content:""}.si-twitter-square::before{content:""}.si-facebook-square::before{content:""}.si-camera-retro::before{content:""}.si-key::before{content:""}.si-cogs::before{content:""}.si-comments::before{content:""}.si-thumbs-o-up::before{content:""}.si-thumbs-o-down::before{content:""}.si-star-half::before{content:""}.si-heart-o::before{content:""}.si-sign-out::before{content:""}.si-linkedin-square::before{content:""}.si-thumb-tack::before{content:""}.si-external-link::before{content:""}.si-sign-in::before{content:""}.si-trophy::before{content:""}.si-github-square::before{content:""}.si-upload::before{content:""}.si-lemon-o::before{content:""}.si-phone::before{content:""}.si-square-o::before{content:""}.si-bookmark-o::before{content:""}.si-phone-square::before{content:""}.si-twitter::before{content:""}.si-facebook::before{content:""}.si-github::before{content:""}.si-unlock::before{content:""}.si-credit-card::before{content:""}.si-feed::before{content:""}.si-hdd-o::before{content:""}.si-bullhorn::before{content:""}.si-bell-o::before{content:""}.si-certificate::before{content:""}.si-hand-o-right::before{content:""}.si-hand-o-left::before{content:""}.si-hand-o-up::before{content:""}.si-hand-o-down::before{content:""}.si-arrow-circle-left::before{content:""}.si-arrow-circle-right::before{content:""}.si-arrow-circle-up::before{content:""}.si-arrow-circle-down::before{content:""}.si-globe::before{content:""}.si-wrench::before{content:""}.si-tasks::before{content:""}.si-filter::before{content:""}.si-briefcase::before{content:""}.si-arrows-alt::before{content:""}.si-group::before{content:""}.si-chain::before{content:""}.si-cloud::before{content:""}.si-flask::before{content:""}.si-cut::before{content:""}.si-copy::before{content:""}.si-paperclip::before{content:""}.si-floppy-o::before{content:""}.si-square::before{content:""}.si-bars::before{content:""}.si-list-ul::before{content:""}.si-list-ol::before{content:""}.si-strikethrough::before{content:""}.si-underline::before{content:""}.si-table::before{content:""}.si-magic::before{content:""}.si-truck::before{content:""}.si-pinterest::before{content:""}.si-pinterest-square::before{content:""}.si-google-plus-square::before{content:""}.si-google-plus::before{content:""}.si-money::before{content:""}.si-caret-down::before{content:""}.si-caret-up::before{content:""}.si-caret-left::before{content:""}.si-caret-right::before{content:""}.si-columns::before{content:""}.si-sort::before{content:""}.si-sort-desc::before{content:""}.si-sort-asc::before{content:""}.si-envelope::before{content:""}.si-linkedin::before{content:""}.si-rotate-left::before{content:""}.si-gavel::before{content:""}.si-dashboard::before{content:""}.si-comment-o::before{content:""}.si-comments-o::before{content:""}.si-bolt::before{content:""}.si-sitemap::before{content:""}.si-umbrella::before{content:""}.si-clipboard::before{content:""}.si-lightbulb-o::before{content:""}.si-exchange::before{content:""}.si-cloud-download::before{content:""}.si-cloud-upload::before{content:""}.si-user-md::before{content:""}.si-stethoscope::before{content:""}.si-suitcase::before{content:""}.si-bell::before{content:""}.si-coffee::before{content:""}.si-cutlery::before{content:""}.si-file-text-o::before{content:""}.si-building-o::before{content:""}.si-hospital-o::before{content:""}.si-ambulance::before{content:""}.si-medkit::before{content:""}.si-fighter-jet::before{content:""}.si-beer::before{content:""}.si-h-square::before{content:""}.si-plus-square::before{content:""}.si-angle-double-left::before{content:""}.si-angle-double-right::before{content:""}.si-angle-double-up::before{content:""}.si-angle-double-down::before{content:""}.si-angle-left::before{content:""}.si-angle-right::before{content:""}.si-angle-up::before{content:""}.si-angle-down::before{content:""}.si-desktop::before{content:""}.si-laptop::before{content:""}.si-tablet::before{content:""}.si-mobile::before{content:""}.si-circle-o::before{content:""}.si-quote-left::before{content:""}.si-quote-right::before{content:""}.si-spinner::before{content:""}.si-circle::before{content:""}.si-mail-reply::before{content:""}.si-github-alt::before{content:""}.si-folder-o::before{content:""}.si-folder-open-o::before{content:""}.si-smile-o::before{content:""}.si-frown-o::before{content:""}.si-meh-o::before{content:""}.si-gamepad::before{content:""}.si-keyboard-o::before{content:""}.si-flag-o::before{content:""}.si-flag-checkered::before{content:""}.si-terminal::before{content:""}.si-code::before{content:""}.si-mail-reply-all::before{content:""}.si-star-half-empty::before{content:""}.si-location-arrow::before{content:""}.si-crop::before{content:""}.si-code-fork::before{content:""}.si-chain-broken::before{content:""}.si-question::before{content:""}.si-info::before{content:""}.si-exclamation::before{content:""}.si-superscript::before{content:""}.si-subscript::before{content:""}.si-eraser::before{content:""}.si-puzzle-piece::before{content:""}.si-microphone::before{content:""}.si-microphone-slash::before{content:""}.si-shield::before{content:""}.si-calendar-o::before{content:""}.si-fire-extinguisher::before{content:""}.si-rocket::before{content:""}.si-maxcdn::before{content:""}.si-chevron-circle-left::before{content:""}.si-chevron-circle-right::before{content:""}.si-chevron-circle-up::before{content:""}.si-chevron-circle-down::before{content:""}.si-html5::before{content:""}.si-css3::before{content:""}.si-anchor::before{content:""}.si-unlock-alt::before{content:""}.si-bullseye::before{content:""}.si-ellipsis-h::before{content:""}.si-ellipsis-v::before{content:""}.si-rss-square::before{content:""}.si-play-circle::before{content:""}.si-ticket::before{content:""}.si-minus-square::before{content:""}.si-minus-square-o::before{content:""}.si-level-up::before{content:""}.si-level-down::before{content:""}.si-check-square::before{content:""}.si-pencil-square::before{content:""}.si-external-link-square::before{content:""}.si-share-square::before{content:""}.si-compass::before{content:""}.si-caret-square-o-down::before{content:""}.si-caret-square-o-up::before{content:""}.si-caret-square-o-right::before{content:""}.si-eur::before{content:""}.si-gbp::before{content:""}.si-dollar::before{content:""}.si-inr::before{content:""}.si-cny::before{content:""}.si-rouble::before{content:""}.si-krw::before{content:""}.si-bitcoin::before{content:""}.si-file::before{content:""}.si-file-text::before{content:""}.si-sort-alpha-asc::before{content:""}.si-sort-alpha-desc::before{content:""}.si-sort-amount-asc::before{content:""}.si-sort-amount-desc::before{content:""}.si-sort-numeric-asc::before{content:""}.si-sort-numeric-desc::before{content:""}.si-thumbs-up::before{content:""}.si-thumbs-down::before{content:""}.si-youtube-square::before{content:""}.si-youtube::before{content:""}.si-xing::before{content:""}.si-xing-square::before{content:""}.si-youtube-play::before{content:""}.si-dropbox::before{content:""}.si-stack-overflow::before{content:""}.si-instagram::before{content:""}.si-flickr::before{content:""}.si-adn::before{content:""}.si-bitbucket::before{content:""}.si-bitbucket-square::before{content:""}.si-tumblr::before{content:""}.si-tumblr-square::before{content:""}.si-long-arrow-down::before{content:""}.si-long-arrow-up::before{content:""}.si-long-arrow-left::before{content:""}.si-long-arrow-right::before{content:""}.si-apple::before{content:""}.si-windows::before{content:""}.si-android::before{content:""}.si-linux::before{content:""}.si-dribbble::before{content:""}.si-skype::before{content:""}.si-foursquare::before{content:""}.si-trello::before{content:""}.si-female::before{content:""}.si-male::before{content:""}.si-gittip::before{content:""}.si-sun-o::before{content:""}.si-moon-o::before{content:""}.si-archive::before{content:""}.si-bug::before{content:""}.si-vk::before{content:""}.si-weibo::before{content:""}.si-renren::before{content:""}.si-pagelines::before{content:""}.si-stack-exchange::before{content:""}.si-arrow-circle-o-right::before{content:""}.si-arrow-circle-o-left::before{content:""}.si-caret-square-o-left::before{content:""}.si-dot-circle-o::before{content:""}.si-wheelchair::before{content:""}.si-vimeo-square::before{content:""}.si-try::before{content:""}.si-plus-square-o::before{content:""}.si-space-shuttle::before{content:""}.si-slack::before{content:""}.si-envelope-square::before{content:""}.si-wordpress::before{content:""}.si-openid::before{content:""}.si-bank::before{content:""}.si-graduation-cap::before{content:""}.si-yahoo::before{content:""}.si-google::before{content:""}.si-reddit::before{content:""}.si-reddit-square::before{content:""}.si-stumbleupon-circle::before{content:""}.si-stumbleupon::before{content:""}.si-delicious::before{content:""}.si-digg::before{content:""}.si-pied-piper::before{content:""}.si-pied-piper-alt::before{content:""}.si-drupal::before{content:""}.si-joomla::before{content:""}.si-language::before{content:""}.si-fax::before{content:""}.si-building::before{content:""}.si-child::before{content:""}.si-paw::before{content:""}.si-spoon::before{content:""}.si-cube::before{content:""}.si-cubes::before{content:""}.si-behance::before{content:""}.si-behance-square::before{content:""}.si-steam::before{content:""}.si-steam-square::before{content:""}.si-recycle::before{content:""}.si-automobile::before{content:""}.si-cab::before{content:""}.si-tree::before{content:""}.si-spotify::before{content:""}.si-deviantart::before{content:""}.si-soundcloud::before{content:""}.si-database::before{content:""}.si-file-pdf-o::before{content:""}.si-file-word-o::before{content:""}.si-file-excel-o::before{content:""}.si-file-powerpoint-o::before{content:""}.si-file-image-o::before{content:""}.si-file-archive-o::before{content:""}.si-file-audio-o::before{content:""}.si-file-movie-o::before{content:""}.si-file-code-o::before{content:""}.si-vine::before{content:""}.si-codepen::before{content:""}.si-jsfiddle::before{content:""}.si-life-bouy::before{content:""}.si-circle-o-notch::before{content:""}.si-ra::before{content:""}.si-empire::before{content:""}.si-git-square::before{content:""}.si-git::before{content:""}.si-hacker-news::before{content:""}.si-tencent-weibo::before{content:""}.si-qq::before{content:""}.si-wechat::before{content:""}.si-paper-plane::before{content:""}.si-paper-plane-o::before{content:""}.si-history::before{content:""}.si-circle-thin::before{content:""}.si-header::before{content:""}.si-paragraph::before{content:""}.si-sliders::before{content:""}.si-share-alt::before{content:""}.si-share-alt-square::before{content:""}.si-bomb::before{content:""}.si-futbol-o::before{content:""}.si-tty::before{content:""}.si-binoculars::before{content:""}.si-plug::before{content:""}.si-slideshare::before{content:""}.si-twitch::before{content:""}.si-yelp::before{content:""}.si-newspaper-o::before{content:""}.si-wifi::before{content:""}.si-calculator::before{content:""}.si-paypal::before{content:""}.si-google-wallet::before{content:""}.si-cc-visa::before{content:""}.si-cc-mastercard::before{content:""}.si-cc-discover::before{content:""}.si-cc-amex::before{content:""}.si-cc-paypal::before{content:""}.si-cc-stripe::before{content:""}.si-bell-slash::before{content:""}.si-bell-slash-o::before{content:""}.si-trash::before{content:""}.si-copyright::before{content:""}.si-at::before{content:""}.si-eyedropper::before{content:""}.si-paint-brush::before{content:""}.si-birthday-cake::before{content:""}.si-area-chart::before{content:""}.si-pie-chart::before{content:""}.si-line-chart::before{content:""}.si-lastfm::before{content:""}.si-lastfm-square::before{content:""}.si-toggle-off::before{content:""}.si-toggle-on::before{content:""}.si-bicycle::before{content:""}.si-bus::before{content:""}.si-ioxhost::before{content:""}.si-angellist::before{content:""}.si-cc::before{content:""}.si-ils::before{content:""}.si-meanpath::before{content:""}.si-buysellads::before{content:""}.si-connectdevelop::before{content:""}.si-dashcube::before{content:""}.si-forumbee::before{content:""}.si-leanpub::before{content:""}.si-sellsy::before{content:""}.si-shirtsinbulk::before{content:""}.si-simplybuilt::before{content:""}.si-skyatlas::before{content:""}.si-cart-plus::before{content:""}.si-cart-arrow-down::before{content:""}.si-diamond::before{content:""}.si-ship::before{content:""}.si-user-secret::before{content:""}.si-motorcycle::before{content:""}.si-street-view::before{content:""}.si-heartbeat::before{content:""}.si-venus::before{content:""}.si-mars::before{content:""}.si-mercury::before{content:""}.si-intersex::before{content:""}.si-transgender-alt::before{content:""}.si-venus-double::before{content:""}.si-mars-double::before{content:""}.si-venus-mars::before{content:""}.si-mars-stroke::before{content:""}.si-mars-stroke-v::before{content:""}.si-mars-stroke-h::before{content:""}.si-neuter::before{content:""}.si-genderless::before{content:""}.si-facebook-official::before{content:""}.si-pinterest-p::before{content:""}.si-whatsapp::before{content:""}.si-server::before{content:""}.si-user-plus::before{content:""}.si-user-times::before{content:""}.si-bed::before{content:""}.si-viacoin::before{content:""}.si-train::before{content:""}.si-subway::before{content:""}.si-medium::before{content:""}.si-y-combinator::before{content:""}.si-optin-monster::before{content:""}.si-opencart::before{content:""}.si-expeditedssl::before{content:""}.si-battery-4::before{content:""}.si-battery-3::before{content:""}.si-battery-2::before{content:""}.si-battery-1::before{content:""}.si-battery-0::before{content:""}.si-mouse-pointer::before{content:""}.si-i-cursor::before{content:""}.si-object-group::before{content:""}.si-object-ungroup::before{content:""}.si-sticky-note::before{content:""}.si-sticky-note-o::before{content:""}.si-cc-jcb::before{content:""}.si-cc-diners-club::before{content:""}.si-clone::before{content:""}.si-balance-scale::before{content:""}.si-hourglass-o::before{content:""}.si-hourglass-1::before{content:""}.si-hourglass-2::before{content:""}.si-hourglass-3::before{content:""}.si-hourglass::before{content:""}.si-hand-grab-o::before{content:""}.si-hand-paper-o::before{content:""}.si-hand-scissors-o::before{content:""}.si-hand-lizard-o::before{content:""}.si-hand-spock-o::before{content:""}.si-hand-pointer-o::before{content:""}.si-hand-peace-o::before{content:""}.si-trademark::before{content:""}.si-registered::before{content:""}.si-creative-commons::before{content:""}.si-gg::before{content:""}.si-gg-circle::before{content:""}.si-tripadvisor::before{content:""}.si-odnoklassniki::before{content:""}.si-odnoklassniki-square::before{content:""}.si-get-pocket::before{content:""}.si-wikipedia-w::before{content:""}.si-safari::before{content:""}.si-chrome::before{content:""}.si-firefox::before{content:""}.si-opera::before{content:""}.si-internet-explorer::before{content:""}.si-television::before{content:""}.si-contao::before{content:""}.si-500px::before{content:""}.si-amazon::before{content:""}.si-calendar-plus-o::before{content:""}.si-calendar-minus-o::before{content:""}.si-calendar-times-o::before{content:""}.si-calendar-check-o::before{content:""}.si-industry::before{content:""}.si-map-pin::before{content:""}.si-map-signs::before{content:""}.si-map-o::before{content:""}.si-map::before{content:""}.si-commenting::before{content:""}.si-commenting-o::before{content:""}.si-houzz::before{content:""}.si-vimeo::before{content:""}.si-black-tie::before{content:""}.si-fonticons::before{content:""}.si-lg{font-size:1.33333333em;line-height:0.75em;vertical-align:-15%}.si-2x{font-size:2em}.si-3x{font-size:3em}.si-4x{font-size:4em}.si-5x{font-size:5em}.si-fw{text-align:center;width:1.28571429em}.si-border{border-radius:.1em;padding:.2em .25em .15em;border:solid 0.08em}.si-pull-left{float:left;margin-right:.3em}.si-pull-right{float:right;margin-left:.3em}.si-rotate-90{-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);-o-transform:rotate(90deg);transform:rotate(90deg)}.si-rotate-180{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg)}.si-rotate-270{-webkit-transform:rotate(270deg);-moz-transform:rotate(270deg);-ms-transform:rotate(270deg);-o-transform:rotate(270deg);transform:rotate(270deg)}.si-flip-horizontal{-webkit-transform:scale(-1, 1);-moz-transform:scale(-1, 1);-ms-transform:scale(-1, 1);-o-transform:scale(-1, 1);transform:scale(-1, 1)}.si-flip-vertical{-webkit-transform:scale(1, -1);-moz-transform:scale(1, -1);-ms-transform:scale(1, -1);-o-transform:scale(1, -1);transform:scale(1, -1)}.si-inverse{-webkit-filter:invert(100%);filter:invert(100%)}.si-spin{-webkit-animation:si-animation-spin 2s infinite linear;-moz-animation:si-animation-spin 2s infinite linear;animation:si-animation-spin 2s infinite linear}.si-pulse{-webkit-animation:si-animation-spin 1s infinite steps(8);-moz-animation:si-animation-spin 1s infinite steps(8);animation:si-animation-spin 1s infinite steps(8)}.si-ul{padding-left:0;list-style-type:none;margin-left:2.14285714em}.si-ul>li{position:relative}.si-ul>li .si-li{text-align:center;position:absolute;left:-2.14285714em;width:2.14285714em;top:0.14285714em}.si-ul>li .si-li .si-lg{left:-1.85714286em}.si-stack{width:2em;height:2em;line-height:2em;vertical-align:middle;position:relative;display:inline-block}.si-stack .si-stack-1x,.si-stack .si-stack-2x{left:0;width:100%;text-align:center;position:absolute}.si-stack .si-stack-1x{line-height:inherit}.si-stack .si-stack-2x{font-size:2em}@-webkit-keyframes si-animation-spin{0%{-webkit-transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg)}}@-moz-keyframes si-animation-spin{0%{-moz-transform:rotate(0deg)}100%{-moz-transform:rotate(359deg)}}@keyframes si-animation-spin{0%{-webkit-transform:rotate(0deg);-moz-transform:rotate(0deg);-ms-transform:rotate(0deg);-o-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);-moz-transform:rotate(359deg);-ms-transform:rotate(359deg);-o-transform:rotate(359deg);transform:rotate(359deg)}}.plugin-menu-page-animation-spin{-webkit-animation-duration:0.75s;-moz-animation-duration:0.75s;animation-duration:0.75s;-webkit-animation-fill-mode:both;-moz-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation-timing-function:linear;-moz-animation-timing-function:linear;animation-timing-function:linear;-webkit-animation-iteration-count:infinite;-moz-animation-iteration-count:infinite;animation-iteration-count:infinite;-webkit-animation-name:plugin-menu-page-animation-spin;-moz-animation-name:plugin-menu-page-animation-spin;animation-name:plugin-menu-page-animation-spin}@-webkit-keyframes plugin-menu-page-animation-spin{0%{-webkit-transform:rotate(0deg)}100%{-webkit-transform:rotate(360deg)}}@-moz-keyframes plugin-menu-page-animation-spin{0%{-moz-transform:rotate(0deg)}100%{-moz-transform:rotate(360deg)}}@keyframes plugin-menu-page-animation-spin{0%{-webkit-transform:rotate(0deg);-moz-transform:rotate(0deg);-ms-transform:rotate(0deg);-o-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(360deg);-moz-transform:rotate(360deg);-ms-transform:rotate(360deg);-o-transform:rotate(360deg);transform:rotate(360deg)}}html{overflow-y:scroll}#wpwrap{position:relative}#wpwrap::after{top:0;right:0;bottom:0;left:0;z-index:-1;position:absolute;content:'';opacity:0.25;background:url("../images/bg.png")}#wpwrap .updated,#wpwrap .error{margin:1.25em 1.25em 1.25em 0.25em}.plugin-menu-page{min-width:800px;margin:1.25em 1.25em 1.25em 0.25em}.plugin-menu-page,.plugin-menu-page p{font-size:14px}.plugin-menu-page a{color:#033A63}.plugin-menu-page a:hover,.plugin-menu-page a:active{color:#467629}.plugin-menu-page p:first-child,.plugin-menu-page pre:first-child{margin-top:0}.plugin-menu-page p:last-child,.plugin-menu-page pre:last-child{margin-bottom:0}.plugin-menu-page code{border-radius:3px;padding:0.1em 0.25em;background:rgba(178,178,178,0.25);font-family:'Menlo', 'Monaco', 'Consolas', 'Courier New', monospace}.plugin-menu-page pre.code{padding:0;background:none}.plugin-menu-page pre.code>code{font-size:90%;overflow-x:auto;max-width:100%;border-radius:4px;padding:1em;display:block;color:#eee;background:#222;box-shadow:0 0 5px 1px #000 inset}.plugin-menu-page img{border:0}.plugin-menu-page img.screenshot{float:right;border-radius:4px;padding:0.5em;margin:0 0 2em 2em;background:#fff;border:1px solid #afafaf;box-shadow:0 0 5px 0 rgba(0,0,0,0.2) inset}.plugin-menu-page hr{border:0;padding:0;height:1px;margin:1em 0;background:linear-gradient(to left, transparent, rgba(0,0,0,0.75), transparent)}.plugin-menu-page label{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.plugin-menu-page label.switch-primary{font-size:130%;margin:0;padding:0.5em;border-radius:4px;display:inline;color:#000;background:#f1e982;border:1px solid rgba(0,0,0,0.07);box-shadow:-1px -1px 0 0 rgba(0,0,0,0.25) inset,1px 1px 0 0 #fff inset}.plugin-menu-page select,.plugin-menu-page textarea,.plugin-menu-page select:focus,.plugin-menu-page textarea:focus,.plugin-menu-page input:not([type='radio']):not([type='checkbox']),.plugin-menu-page input:not([type='radio']):not([type='checkbox']):focus{width:100%;line-height:1.3em;margin:0;padding:0.25em 0.5em;border-radius:4px;box-sizing:border-box;color:#333;background:#e8e8e8;border:1px solid #848484;box-shadow:0 0 2px 0 rgba(132,132,132,0.5) inset}.plugin-menu-page select,.plugin-menu-page select:focus{box-shadow:0 1px 0 0 #fff inset,0 -2px 3px 0 rgba(132,132,132,0.25) inset}.plugin-menu-page select,.plugin-menu-page select:focus,.plugin-menu-page input:not([type='radio']):not([type='checkbox']),.plugin-menu-page input:not([type='radio']):not([type='checkbox']):focus{height:2em}.plugin-menu-page select:focus,.plugin-menu-page textarea:focus,.plugin-menu-page input:not([type='radio']):not([type='checkbox']):focus{color:#000;background:#e2e2e2}.plugin-menu-page input[disabled],.plugin-menu-page select[disabled],.plugin-menu-page textarea[disabled]{opacity:0.5}.plugin-menu-page input::-webkit-input-placeholder,.plugin-menu-page textarea::-webkit-input-placeholder{font-style:italic;color:rgba(0,0,0,0.2)}.plugin-menu-page input::-moz-placeholder,.plugin-menu-page textarea::-moz-placeholder{font-style:italic;color:rgba(0,0,0,0.2)}.plugin-menu-page input:-moz-placeholder,.plugin-menu-page textarea:-moz-placeholder{font-style:italic;color:rgba(0,0,0,0.2)}.plugin-menu-page input:-ms-input-placeholder,.plugin-menu-page textarea:-ms-input-placeholder{font-style:italic;color:rgba(0,0,0,0.2)}.plugin-menu-page table{margin:1em 0}.plugin-menu-page button{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;font-size:150%;font-weight:bold;line-height:1em;outline:none;cursor:pointer;border-radius:4px;margin:0;padding:0.25em 0.5em;box-sizing:border-box;color:#fff;background:#033A63;border:1px solid rgba(0,0,0,0.5);box-shadow:0 1px 1px 0 rgba(0,0,0,0.25),-1px -1px 0 0 rgba(0,0,0,0.2) inset,1px 1px 0 0 rgba(255,255,255,0.1) inset}.plugin-menu-page button:hover{background:#467629}.plugin-menu-page button[type='submit']{background:#467629}.plugin-menu-page button[type='submit']:hover{background:#033A63}.plugin-menu-page button:active{-webkit-transform:scale(0.98, 0.98);-moz-transform:scale(0.98, 0.98);-ms-transform:scale(0.98, 0.98);-o-transform:scale(0.98, 0.98);transform:scale(0.98, 0.98)}.plugin-menu-page .info,.plugin-menu-page .notice,.plugin-menu-page .warning,.plugin-menu-page .error{border-radius:4px;padding:0.5em;margin:1em 0}.plugin-menu-page .info{background:#cadfed;border:1px solid #216095}.plugin-menu-page .notice{background:#fffde8;border:1px solid #e6db55}.plugin-menu-page .warning{background:#ffefd3;border:1px solid #e6db55}.plugin-menu-page .error{background:pink;border:1px solid #711e1e}.plugin-menu-page .monospace{font-family:'Menlo', 'Monaco', 'Consolas', 'Courier New', monospace}.plugin-menu-page textarea.monospace{white-space:pre}.plugin-menu-page .clearfix::before,.plugin-menu-page .clearfix::after{display:table;content:' '}.plugin-menu-page .clearfix::after{clear:both}.plugin-menu-page-heading .plugin-menu-page-restore-defaults,.plugin-menu-page-heading .plugin-menu-page-panel-togglers{float:right;margin:0 1em 0 0}.plugin-menu-page-heading .plugin-menu-page-panel-togglers button{background:#033A63 !important}.plugin-menu-page-heading .plugin-menu-page-upsells{float:right;clear:right;text-align:right;max-width:350px;margin:1em 0 0}.plugin-menu-page-heading .plugin-menu-page-upsells a{text-decoration:none;line-height:1.5em;margin:0 0.5em;display:inline-block}.plugin-menu-page-heading .plugin-menu-page-support-links,.plugin-menu-page-heading .plugin-menu-page-mailing-list-links{float:right;clear:right;text-align:right;max-width:400px;margin:.5em 0 0}.plugin-menu-page-heading .plugin-menu-page-support-links a,.plugin-menu-page-heading .plugin-menu-page-mailing-list-links a{text-decoration:none;margin:0 0.5em;display:inline-block}.plugin-menu-page-heading .plugin-menu-page-version{float:right;clear:right;min-width:350px;margin:0.5em 0 0 0;text-align:right}.plugin-menu-page-body{position:relative}.plugin-menu-page-section-heading{margin:1em 0}.plugin-menu-page-section-heading>small{font-size:65%;font-style:italic;margin:0;display:block;opacity:0.5}.plugin-menu-page-panel{margin:1em 0}.plugin-menu-page-panel:first-child{margin-top:0}.plugin-menu-page-panel .plugin-menu-page-panel-heading{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;text-decoration:none;padding:10px;font-size:150%;line-height:1.125em;font-weight:bold;border-radius:4px;display:block;cursor:pointer;background:#033A63;background:linear-gradient(to right, #033A63, #20669A);color:#eee !important;box-shadow:0 2px 2px 0 rgba(0,0,0,0.25)}.plugin-menu-page-panel .plugin-menu-page-panel-heading::after{font:normal normal normal 14px/1 sharkicons;text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased;font-smoothing:antialiased;display:inline-block;font-size:inherit;text-decoration:inherit;text-transform:none;content:""}.plugin-menu-page-panel .plugin-menu-page-panel-heading:hover,.plugin-menu-page-panel .plugin-menu-page-panel-heading.open{color:#fff !important}.plugin-menu-page-panel .plugin-menu-page-panel-heading::after{font-size:80%;float:right;margin:0 0 0 5px}.plugin-menu-page-panel .plugin-menu-page-panel-heading.open::after{content:""}.plugin-menu-page-panel-heading.pro-preview-feature{background:#216095}.pro-preview-feature::after{font-variant:small-caps !important;font-family:sans-serif !important;content:'pro version only' !important;margin-left:15px;background:#216095;color:#FFFFFF;padding:0 5px 2px 5px;font-weight:normal}.plugin-menu-page-panel-heading.pro-preview-additional-features{background:#216095}.pro-preview-additional-features::after{font-variant:small-caps !important;font-family:sans-serif !important;content:'additional pro version only features' !important;margin-left:15px;background:#216095;color:#FFFFFF;padding:0 5px 2px 5px;font-weight:normal}.plugin-menu-page-panel .plugin-menu-page-panel-heading>.si{text-align:center;width:1.28571429em;margin-right:.25em}.plugin-menu-page-panel .plugin-menu-page-panel-body{width:99%;margin:0 auto;display:none;padding:1.2em;border-bottom-left-radius:4px;border-bottom-right-radius:4px;box-sizing:border-box;color:#222;border:1px solid #848484;background:#fff;box-shadow:0 1px 1px 0 rgba(0,0,0,0.25),0 3px 1px -1px rgba(0,0,0,0.25) inset}.plugin-menu-page-panel .plugin-menu-page-panel-body.open{display:block}.plugin-menu-page-panel .plugin-menu-page-panel-body p{font-size:90%;color:#666}.plugin-menu-page-panel .plugin-menu-page-panel-body p.notice,.plugin-menu-page-panel .plugin-menu-page-panel-body p.info,.plugin-menu-page-panel .plugin-menu-page-panel-body p.warning,.plugin-menu-page-panel .plugin-menu-page-panel-body p.error{color:#000}.plugin-menu-page-panel .plugin-menu-page-panel-body h3{margin:0 0 0.5em}.plugin-menu-page-panel .plugin-menu-page-panel-body h3:first-child{margin-top:0}.plugin-menu-page-panel .plugin-menu-page-panel-body h3+p{margin-top:0}.plugin-menu-page-panel .plugin-menu-page-panel-body a.dotted{text-decoration:none;border-bottom:1px dotted}.plugin-menu-page-panel .plugin-menu-page-panel-body.pro-preview,.plugin-menu-page-panel .plugin-menu-page-panel-body .pro-preview{opacity:0.5}.plugin-menu-page-save{margin-top:2em}.plugin-menu-page-save button{line-height:1.3em;width:100%}
2
 
1
+ @font-face{font-family:sharkicons;src:url("../../vendor/websharks/sharkicons/src/fonts/sharkicons.eot?v160221");src:url("../../vendor/websharks/sharkicons/src/fonts/sharkicons.eot?#iefix&v160221") format("embedded-opentype"),url("../../vendor/websharks/sharkicons/src/fonts/sharkicons.ttf?v160221") format("truetype"),url("../../vendor/websharks/sharkicons/src/fonts/sharkicons.woff?v160221") format("woff"),url("../../vendor/websharks/sharkicons/src/fonts/sharkicons.svg?v160221#sharkicons") format("svg");font-weight:normal;font-style:normal}.si::before{font:normal normal normal 14px/1 sharkicons;text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased;font-smoothing:antialiased;display:inline-block;font-size:inherit;text-decoration:inherit;text-transform:none}.si-broom::before{content:""}.si-comment-mail-one::before{content:""}.si-comment-mail::before{content:""}.si-s2member::before{content:""}.si-websharks::before{content:""}.si-wp-kb-articles::before{content:""}.si-zencache-logo::before{content:""}.si-zencache::before{content:""}.si-wp-sharks::before{content:""}.si-wp-sharks-fin::before{content:""}.si-comet-cache::before{content:""}.si-comet-cache-logo::before{content:""}.si-comet-cache-comet::before{content:""}.si-feat-watch::before{content:""}.si-feat-server::before{content:""}.si-feat-layers::before{content:""}.si-feat-box::before{content:""}.si-feat-ellipsis::before{content:""}.si-typi-group::before{content:""}.si-enty-bookmark::before{content:""}.si-enty-bookmarks::before{content:""}.si-enty-open-book::before{content:""}.si-enty-archive::before{content:""}.si-enty-area-graph::before{content:""}.si-enty-bucket::before{content:""}.si-enty-colors::before{content:""}.si-enty-copy::before{content:""}.si-enty-drive::before{content:""}.si-enty-feather::before{content:""}.si-enty-gauge::before{content:""}.si-enty-hand::before{content:""}.si-enty-lab-flask::before{content:""}.si-enty-mask::before{content:""}.si-enty-medal::before{content:""}.si-enty-exclamation::before{content:""}.si-enty-palette::before{content:""}.si-enty-ruler::before{content:""}.si-enty-shop::before{content:""}.si-enty-basket::before{content:""}.si-enty-cart::before{content:""}.si-enty-traffic-cone::before{content:""}.si-enty-tree::before{content:""}.si-enty-trophy::before{content:""}.si-enty-v-card::before{content:""}.si-enty-google-hangouts::before{content:""}.si-eleg-line-graph::before{content:""}.si-eleg-male::before{content:""}.si-eleg-female::before{content:""}.si-eleg-atom::before{content:""}.si-broc-cart::before{content:""}.si-broc-crap::before{content:""}.si-broc-atom::before{content:""}.si-icom-headphones::before{content:""}.si-icom-barcode::before{content:""}.si-icom-user::before{content:""}.si-icom-users::before{content:""}.si-icom-user-plus::before{content:""}.si-icom-user-minus::before{content:""}.si-icom-user-check::before{content:""}.si-icom-user-tie::before{content:""}.si-icom-key::before{content:""}.si-icom-key2::before{content:""}.si-icom-happy::before{content:""}.si-icom-happy2::before{content:""}.si-icom-smile::before{content:""}.si-icom-smile2::before{content:""}.si-icom-tongue::before{content:""}.si-icom-tongue2::before{content:""}.si-icom-sad::before{content:""}.si-icom-sad2::before{content:""}.si-icom-wink::before{content:""}.si-icom-wink2::before{content:""}.si-icom-grin::before{content:""}.si-icom-grin2::before{content:""}.si-icom-cool::before{content:""}.si-icom-cool2::before{content:""}.si-icom-angry::before{content:""}.si-icom-angry2::before{content:""}.si-icom-evil::before{content:""}.si-icom-evil2::before{content:""}.si-icom-shocked::before{content:""}.si-icom-shocked2::before{content:""}.si-icom-baffled::before{content:""}.si-icom-baffled2::before{content:""}.si-icom-confused::before{content:""}.si-icom-confused2::before{content:""}.si-icom-neutral::before{content:""}.si-icom-neutral2::before{content:""}.si-icom-hipster::before{content:""}.si-icom-hipster2::before{content:""}.si-icom-wondering::before{content:""}.si-icom-wondering2::before{content:""}.si-icom-sleepy::before{content:""}.si-icom-sleepy2::before{content:""}.si-icom-frustrated::before{content:""}.si-icom-frustrated2::before{content:""}.si-icom-crying::before{content:""}.si-icom-crying2::before{content:""}.si-icom-spell-check::before{content:""}.si-icom-command-key::before{content:""}.si-icom-shift-key::before{content:""}.si-icom-control-key::before{content:""}.si-icom-option-key::before{content:""}.si-icom-wordpress::before{content:""}.si-icom-wordpress-square::before{content:""}.si-icom-yahoo::before{content:""}.si-icom-linux::before{content:""}.si-icom-finder::before{content:""}.si-icom-android::before{content:""}.si-icom-reddit::before{content:""}.si-icom-paypal::before{content:""}.si-icom-git::before{content:""}.si-octi-alignment-align::before{content:""}.si-octi-alignment-aligned-to::before{content:""}.si-octi-alignment-unalign::before{content:""}.si-octi-bookmark::before{content:""}.si-octi-broadcast::before{content:""}.si-octi-browser::before{content:""}.si-octi-checklist::before{content:""}.si-octi-circuit-board::before{content:""}.si-octi-clippy::before{content:""}.si-octi-cloud-download::before{content:""}.si-octi-cloud-upload::before{content:""}.si-octi-comment::before{content:""}.si-octi-comments::before{content:""}.si-octi-tach::before{content:""}.si-octi-device-camera::before{content:""}.si-octi-device-camera-video::before{content:""}.si-octi-device-desktop::before{content:""}.si-octi-diff::before{content:""}.si-octi-file-binary::before{content:""}.si-octi-file-media::before{content:""}.si-octi-file-submodule::before{content:""}.si-octi-file-symlink-directory::before{content:""}.si-octi-file-symlink-file::before{content:""}.si-octi-fold::before{content:""}.si-octi-git-branch::before{content:""}.si-octi-git-commit::before{content:""}.si-octi-git-compare::before{content:""}.si-octi-git-merge::before{content:""}.si-octi-git-pull-request::before{content:""}.si-octi-graph::before{content:""}.si-octi-home::before{content:""}.si-octi-horizontal-rule::before{content:""}.si-octi-key::before{content:""}.si-octi-light-bulb::before{content:""}.si-octi-link-external::before{content:""}.si-octi-lock::before{content:""}.si-octi-markdown::before{content:""}.si-octi-microscope::before{content:""}.si-octi-mirror::before{content:""}.si-octi-move-down::before{content:""}.si-octi-move-left::before{content:""}.si-octi-move-right::before{content:""}.si-octi-move-up::before{content:""}.si-octi-mute::before{content:""}.si-octi-organization::before{content:""}.si-octi-package::before{content:""}.si-octi-paintcan::before{content:""}.si-octi-person::before{content:""}.si-octi-plug::before{content:""}.si-octi-podium::before{content:""}.si-octi-pulse::before{content:""}.si-octi-puzzle::before{content:""}.si-octi-repo::before{content:""}.si-octi-repo-clone::before{content:""}.si-octi-repo-force-push::before{content:""}.si-octi-repo-forked::before{content:""}.si-octi-repo-pull::before{content:""}.si-octi-repo-push::before{content:""}.si-octi-rocket::before{content:""}.si-octi-ruby::before{content:""}.si-octi-screen-full::before{content:""}.si-octi-screen-normal::before{content:""}.si-octi-sign-in::before{content:""}.si-octi-sign-out::before{content:""}.si-octi-split::before{content:""}.si-octi-squirrel::before{content:""}.si-octi-steps::before{content:""}.si-octi-tag::before{content:""}.si-octi-telescope::before{content:""}.si-octi-terminal::before{content:""}.si-octi-unfold::before{content:""}.si-octi-versions::before{content:""}.si-glass::before{content:""}.si-music::before{content:""}.si-search::before{content:""}.si-envelope-o::before{content:""}.si-heart::before{content:""}.si-star::before{content:""}.si-star-o::before{content:""}.si-user::before{content:""}.si-film::before{content:""}.si-th-large::before{content:""}.si-th::before{content:""}.si-th-list::before{content:""}.si-check::before{content:""}.si-close::before{content:""}.si-search-plus::before{content:""}.si-search-minus::before{content:""}.si-power-off::before{content:""}.si-signal::before{content:""}.si-cog::before{content:""}.si-trash-o::before{content:""}.si-home::before{content:""}.si-file-o::before{content:""}.si-clock-o::before{content:""}.si-road::before{content:""}.si-download::before{content:""}.si-arrow-circle-o-down::before{content:""}.si-arrow-circle-o-up::before{content:""}.si-inbox::before{content:""}.si-play-circle-o::before{content:""}.si-repeat::before{content:""}.si-refresh::before{content:""}.si-list-alt::before{content:""}.si-lock::before{content:""}.si-flag::before{content:""}.si-headphones::before{content:""}.si-volume-off::before{content:""}.si-volume-down::before{content:""}.si-volume-up::before{content:""}.si-qrcode::before{content:""}.si-barcode::before{content:""}.si-tag::before{content:""}.si-tags::before{content:""}.si-book::before{content:""}.si-bookmark::before{content:""}.si-print::before{content:""}.si-camera::before{content:""}.si-font::before{content:""}.si-bold::before{content:""}.si-italic::before{content:""}.si-text-height::before{content:""}.si-text-width::before{content:""}.si-align-left::before{content:""}.si-align-center::before{content:""}.si-align-right::before{content:""}.si-align-justify::before{content:""}.si-list::before{content:""}.si-dedent::before{content:""}.si-indent::before{content:""}.si-video-camera::before{content:""}.si-image::before{content:""}.si-pencil::before{content:""}.si-map-marker::before{content:""}.si-adjust::before{content:""}.si-tint::before{content:""}.si-edit::before{content:""}.si-share-square-o::before{content:""}.si-check-square-o::before{content:""}.si-arrows::before{content:""}.si-step-backward::before{content:""}.si-fast-backward::before{content:""}.si-backward::before{content:""}.si-play::before{content:""}.si-pause::before{content:""}.si-stop::before{content:""}.si-forward::before{content:""}.si-fast-forward::before{content:""}.si-step-forward::before{content:""}.si-eject::before{content:""}.si-chevron-left::before{content:""}.si-chevron-right::before{content:""}.si-plus-circle::before{content:""}.si-minus-circle::before{content:""}.si-times-circle::before{content:""}.si-check-circle::before{content:""}.si-question-circle::before{content:""}.si-info-circle::before{content:""}.si-crosshairs::before{content:""}.si-times-circle-o::before{content:""}.si-check-circle-o::before{content:""}.si-ban::before{content:""}.si-arrow-left::before{content:""}.si-arrow-right::before{content:""}.si-arrow-up::before{content:""}.si-arrow-down::before{content:""}.si-mail-forward::before{content:""}.si-expand::before{content:""}.si-compress::before{content:""}.si-plus::before{content:""}.si-minus::before{content:""}.si-asterisk::before{content:""}.si-exclamation-circle::before{content:""}.si-gift::before{content:""}.si-leaf::before{content:""}.si-fire::before{content:""}.si-eye::before{content:""}.si-eye-slash::before{content:""}.si-exclamation-triangle::before{content:""}.si-plane::before{content:""}.si-calendar::before{content:""}.si-random::before{content:""}.si-comment::before{content:""}.si-magnet::before{content:""}.si-chevron-up::before{content:""}.si-chevron-down::before{content:""}.si-retweet::before{content:""}.si-shopping-cart::before{content:""}.si-folder::before{content:""}.si-folder-open::before{content:""}.si-arrows-v::before{content:""}.si-arrows-h::before{content:""}.si-bar-chart::before{content:""}.si-twitter-square::before{content:""}.si-facebook-square::before{content:""}.si-camera-retro::before{content:""}.si-key::before{content:""}.si-cogs::before{content:""}.si-comments::before{content:""}.si-thumbs-o-up::before{content:""}.si-thumbs-o-down::before{content:""}.si-star-half::before{content:""}.si-heart-o::before{content:""}.si-sign-out::before{content:""}.si-linkedin-square::before{content:""}.si-thumb-tack::before{content:""}.si-external-link::before{content:""}.si-sign-in::before{content:""}.si-trophy::before{content:""}.si-github-square::before{content:""}.si-upload::before{content:""}.si-lemon-o::before{content:""}.si-phone::before{content:""}.si-square-o::before{content:""}.si-bookmark-o::before{content:""}.si-phone-square::before{content:""}.si-twitter::before{content:""}.si-facebook::before{content:""}.si-github::before{content:""}.si-unlock::before{content:""}.si-credit-card::before{content:""}.si-feed::before{content:""}.si-hdd-o::before{content:""}.si-bullhorn::before{content:""}.si-bell-o::before{content:""}.si-certificate::before{content:""}.si-hand-o-right::before{content:""}.si-hand-o-left::before{content:""}.si-hand-o-up::before{content:""}.si-hand-o-down::before{content:""}.si-arrow-circle-left::before{content:""}.si-arrow-circle-right::before{content:""}.si-arrow-circle-up::before{content:""}.si-arrow-circle-down::before{content:""}.si-globe::before{content:""}.si-wrench::before{content:""}.si-tasks::before{content:""}.si-filter::before{content:""}.si-briefcase::before{content:""}.si-arrows-alt::before{content:""}.si-group::before{content:""}.si-chain::before{content:""}.si-cloud::before{content:""}.si-flask::before{content:""}.si-cut::before{content:""}.si-copy::before{content:""}.si-paperclip::before{content:""}.si-floppy-o::before{content:""}.si-square::before{content:""}.si-bars::before{content:""}.si-list-ul::before{content:""}.si-list-ol::before{content:""}.si-strikethrough::before{content:""}.si-underline::before{content:""}.si-table::before{content:""}.si-magic::before{content:""}.si-truck::before{content:""}.si-pinterest::before{content:""}.si-pinterest-square::before{content:""}.si-google-plus-square::before{content:""}.si-google-plus::before{content:""}.si-money::before{content:""}.si-caret-down::before{content:""}.si-caret-up::before{content:""}.si-caret-left::before{content:""}.si-caret-right::before{content:""}.si-columns::before{content:""}.si-sort::before{content:""}.si-sort-desc::before{content:""}.si-sort-asc::before{content:""}.si-envelope::before{content:""}.si-linkedin::before{content:""}.si-rotate-left::before{content:""}.si-gavel::before{content:""}.si-dashboard::before{content:""}.si-comment-o::before{content:""}.si-comments-o::before{content:""}.si-bolt::before{content:""}.si-sitemap::before{content:""}.si-umbrella::before{content:""}.si-clipboard::before{content:""}.si-lightbulb-o::before{content:""}.si-exchange::before{content:""}.si-cloud-download::before{content:""}.si-cloud-upload::before{content:""}.si-user-md::before{content:""}.si-stethoscope::before{content:""}.si-suitcase::before{content:""}.si-bell::before{content:""}.si-coffee::before{content:""}.si-cutlery::before{content:""}.si-file-text-o::before{content:""}.si-building-o::before{content:""}.si-hospital-o::before{content:""}.si-ambulance::before{content:""}.si-medkit::before{content:""}.si-fighter-jet::before{content:""}.si-beer::before{content:""}.si-h-square::before{content:""}.si-plus-square::before{content:""}.si-angle-double-left::before{content:""}.si-angle-double-right::before{content:""}.si-angle-double-up::before{content:""}.si-angle-double-down::before{content:""}.si-angle-left::before{content:""}.si-angle-right::before{content:""}.si-angle-up::before{content:""}.si-angle-down::before{content:""}.si-desktop::before{content:""}.si-laptop::before{content:""}.si-tablet::before{content:""}.si-mobile::before{content:""}.si-circle-o::before{content:""}.si-quote-left::before{content:""}.si-quote-right::before{content:""}.si-spinner::before{content:""}.si-circle::before{content:""}.si-mail-reply::before{content:""}.si-github-alt::before{content:""}.si-folder-o::before{content:""}.si-folder-open-o::before{content:""}.si-smile-o::before{content:""}.si-frown-o::before{content:""}.si-meh-o::before{content:""}.si-gamepad::before{content:""}.si-keyboard-o::before{content:""}.si-flag-o::before{content:""}.si-flag-checkered::before{content:""}.si-terminal::before{content:""}.si-code::before{content:""}.si-mail-reply-all::before{content:""}.si-star-half-empty::before{content:""}.si-location-arrow::before{content:""}.si-crop::before{content:""}.si-code-fork::before{content:""}.si-chain-broken::before{content:""}.si-question::before{content:""}.si-info::before{content:""}.si-exclamation::before{content:""}.si-superscript::before{content:""}.si-subscript::before{content:""}.si-eraser::before{content:""}.si-puzzle-piece::before{content:""}.si-microphone::before{content:""}.si-microphone-slash::before{content:""}.si-shield::before{content:""}.si-calendar-o::before{content:""}.si-fire-extinguisher::before{content:""}.si-rocket::before{content:""}.si-maxcdn::before{content:""}.si-chevron-circle-left::before{content:""}.si-chevron-circle-right::before{content:""}.si-chevron-circle-up::before{content:""}.si-chevron-circle-down::before{content:""}.si-html5::before{content:""}.si-css3::before{content:""}.si-anchor::before{content:""}.si-unlock-alt::before{content:""}.si-bullseye::before{content:""}.si-ellipsis-h::before{content:""}.si-ellipsis-v::before{content:""}.si-rss-square::before{content:""}.si-play-circle::before{content:""}.si-ticket::before{content:""}.si-minus-square::before{content:""}.si-minus-square-o::before{content:""}.si-level-up::before{content:""}.si-level-down::before{content:""}.si-check-square::before{content:""}.si-pencil-square::before{content:""}.si-external-link-square::before{content:""}.si-share-square::before{content:""}.si-compass::before{content:""}.si-caret-square-o-down::before{content:""}.si-caret-square-o-up::before{content:""}.si-caret-square-o-right::before{content:""}.si-eur::before{content:""}.si-gbp::before{content:""}.si-dollar::before{content:""}.si-inr::before{content:""}.si-cny::before{content:""}.si-rouble::before{content:""}.si-krw::before{content:""}.si-bitcoin::before{content:""}.si-file::before{content:""}.si-file-text::before{content:""}.si-sort-alpha-asc::before{content:""}.si-sort-alpha-desc::before{content:""}.si-sort-amount-asc::before{content:""}.si-sort-amount-desc::before{content:""}.si-sort-numeric-asc::before{content:""}.si-sort-numeric-desc::before{content:""}.si-thumbs-up::before{content:""}.si-thumbs-down::before{content:""}.si-youtube-square::before{content:""}.si-youtube::before{content:""}.si-xing::before{content:""}.si-xing-square::before{content:""}.si-youtube-play::before{content:""}.si-dropbox::before{content:""}.si-stack-overflow::before{content:""}.si-instagram::before{content:""}.si-flickr::before{content:""}.si-adn::before{content:""}.si-bitbucket::before{content:""}.si-bitbucket-square::before{content:""}.si-tumblr::before{content:""}.si-tumblr-square::before{content:""}.si-long-arrow-down::before{content:""}.si-long-arrow-up::before{content:""}.si-long-arrow-left::before{content:""}.si-long-arrow-right::before{content:""}.si-apple::before{content:""}.si-windows::before{content:""}.si-android::before{content:""}.si-linux::before{content:""}.si-dribbble::before{content:""}.si-skype::before{content:""}.si-foursquare::before{content:""}.si-trello::before{content:""}.si-female::before{content:""}.si-male::before{content:""}.si-gittip::before{content:""}.si-sun-o::before{content:""}.si-moon-o::before{content:""}.si-archive::before{content:""}.si-bug::before{content:""}.si-vk::before{content:""}.si-weibo::before{content:""}.si-renren::before{content:""}.si-pagelines::before{content:""}.si-stack-exchange::before{content:""}.si-arrow-circle-o-right::before{content:""}.si-arrow-circle-o-left::before{content:""}.si-caret-square-o-left::before{content:""}.si-dot-circle-o::before{content:""}.si-wheelchair::before{content:""}.si-vimeo-square::before{content:""}.si-try::before{content:""}.si-plus-square-o::before{content:""}.si-space-shuttle::before{content:""}.si-slack::before{content:""}.si-envelope-square::before{content:""}.si-wordpress::before{content:""}.si-openid::before{content:""}.si-bank::before{content:""}.si-graduation-cap::before{content:""}.si-yahoo::before{content:""}.si-google::before{content:""}.si-reddit::before{content:""}.si-reddit-square::before{content:""}.si-stumbleupon-circle::before{content:""}.si-stumbleupon::before{content:""}.si-delicious::before{content:""}.si-digg::before{content:""}.si-pied-piper::before{content:""}.si-pied-piper-alt::before{content:""}.si-drupal::before{content:""}.si-joomla::before{content:""}.si-language::before{content:""}.si-fax::before{content:""}.si-building::before{content:""}.si-child::before{content:""}.si-paw::before{content:""}.si-spoon::before{content:""}.si-cube::before{content:""}.si-cubes::before{content:""}.si-behance::before{content:""}.si-behance-square::before{content:""}.si-steam::before{content:""}.si-steam-square::before{content:""}.si-recycle::before{content:""}.si-automobile::before{content:""}.si-cab::before{content:""}.si-tree::before{content:""}.si-spotify::before{content:""}.si-deviantart::before{content:""}.si-soundcloud::before{content:""}.si-database::before{content:""}.si-file-pdf-o::before{content:""}.si-file-word-o::before{content:""}.si-file-excel-o::before{content:""}.si-file-powerpoint-o::before{content:""}.si-file-image-o::before{content:""}.si-file-archive-o::before{content:""}.si-file-audio-o::before{content:""}.si-file-movie-o::before{content:""}.si-file-code-o::before{content:""}.si-vine::before{content:""}.si-codepen::before{content:""}.si-jsfiddle::before{content:""}.si-life-bouy::before{content:""}.si-circle-o-notch::before{content:""}.si-ra::before{content:""}.si-empire::before{content:""}.si-git-square::before{content:""}.si-git::before{content:""}.si-hacker-news::before{content:""}.si-tencent-weibo::before{content:""}.si-qq::before{content:""}.si-wechat::before{content:""}.si-paper-plane::before{content:""}.si-paper-plane-o::before{content:""}.si-history::before{content:""}.si-circle-thin::before{content:""}.si-header::before{content:""}.si-paragraph::before{content:""}.si-sliders::before{content:""}.si-share-alt::before{content:""}.si-share-alt-square::before{content:""}.si-bomb::before{content:""}.si-futbol-o::before{content:""}.si-tty::before{content:""}.si-binoculars::before{content:""}.si-plug::before{content:""}.si-slideshare::before{content:""}.si-twitch::before{content:""}.si-yelp::before{content:""}.si-newspaper-o::before{content:""}.si-wifi::before{content:""}.si-calculator::before{content:""}.si-paypal::before{content:""}.si-google-wallet::before{content:""}.si-cc-visa::before{content:""}.si-cc-mastercard::before{content:""}.si-cc-discover::before{content:""}.si-cc-amex::before{content:""}.si-cc-paypal::before{content:""}.si-cc-stripe::before{content:""}.si-bell-slash::before{content:""}.si-bell-slash-o::before{content:""}.si-trash::before{content:""}.si-copyright::before{content:""}.si-at::before{content:""}.si-eyedropper::before{content:""}.si-paint-brush::before{content:""}.si-birthday-cake::before{content:""}.si-area-chart::before{content:""}.si-pie-chart::before{content:""}.si-line-chart::before{content:""}.si-lastfm::before{content:""}.si-lastfm-square::before{content:""}.si-toggle-off::before{content:""}.si-toggle-on::before{content:""}.si-bicycle::before{content:""}.si-bus::before{content:""}.si-ioxhost::before{content:""}.si-angellist::before{content:""}.si-cc::before{content:""}.si-ils::before{content:""}.si-meanpath::before{content:""}.si-buysellads::before{content:""}.si-connectdevelop::before{content:""}.si-dashcube::before{content:""}.si-forumbee::before{content:""}.si-leanpub::before{content:""}.si-sellsy::before{content:""}.si-shirtsinbulk::before{content:""}.si-simplybuilt::before{content:""}.si-skyatlas::before{content:""}.si-cart-plus::before{content:""}.si-cart-arrow-down::before{content:""}.si-diamond::before{content:""}.si-ship::before{content:""}.si-user-secret::before{content:""}.si-motorcycle::before{content:""}.si-street-view::before{content:""}.si-heartbeat::before{content:""}.si-venus::before{content:""}.si-mars::before{content:""}.si-mercury::before{content:""}.si-intersex::before{content:""}.si-transgender-alt::before{content:""}.si-venus-double::before{content:""}.si-mars-double::before{content:""}.si-venus-mars::before{content:""}.si-mars-stroke::before{content:""}.si-mars-stroke-v::before{content:""}.si-mars-stroke-h::before{content:""}.si-neuter::before{content:""}.si-genderless::before{content:""}.si-facebook-official::before{content:""}.si-pinterest-p::before{content:""}.si-whatsapp::before{content:""}.si-server::before{content:""}.si-user-plus::before{content:""}.si-user-times::before{content:""}.si-bed::before{content:""}.si-viacoin::before{content:""}.si-train::before{content:""}.si-subway::before{content:""}.si-medium::before{content:""}.si-y-combinator::before{content:""}.si-optin-monster::before{content:""}.si-opencart::before{content:""}.si-expeditedssl::before{content:""}.si-battery-4::before{content:""}.si-battery-3::before{content:""}.si-battery-2::before{content:""}.si-battery-1::before{content:""}.si-battery-0::before{content:""}.si-mouse-pointer::before{content:""}.si-i-cursor::before{content:""}.si-object-group::before{content:""}.si-object-ungroup::before{content:""}.si-sticky-note::before{content:""}.si-sticky-note-o::before{content:""}.si-cc-jcb::before{content:""}.si-cc-diners-club::before{content:""}.si-clone::before{content:""}.si-balance-scale::before{content:""}.si-hourglass-o::before{content:""}.si-hourglass-1::before{content:""}.si-hourglass-2::before{content:""}.si-hourglass-3::before{content:""}.si-hourglass::before{content:""}.si-hand-grab-o::before{content:""}.si-hand-paper-o::before{content:""}.si-hand-scissors-o::before{content:""}.si-hand-lizard-o::before{content:""}.si-hand-spock-o::before{content:""}.si-hand-pointer-o::before{content:""}.si-hand-peace-o::before{content:""}.si-trademark::before{content:""}.si-registered::before{content:""}.si-creative-commons::before{content:""}.si-gg::before{content:""}.si-gg-circle::before{content:""}.si-tripadvisor::before{content:""}.si-odnoklassniki::before{content:""}.si-odnoklassniki-square::before{content:""}.si-get-pocket::before{content:""}.si-wikipedia-w::before{content:""}.si-safari::before{content:""}.si-chrome::before{content:""}.si-firefox::before{content:""}.si-opera::before{content:""}.si-internet-explorer::before{content:""}.si-television::before{content:""}.si-contao::before{content:""}.si-500px::before{content:""}.si-amazon::before{content:""}.si-calendar-plus-o::before{content:""}.si-calendar-minus-o::before{content:""}.si-calendar-times-o::before{content:""}.si-calendar-check-o::before{content:""}.si-industry::before{content:""}.si-map-pin::before{content:""}.si-map-signs::before{content:""}.si-map-o::before{content:""}.si-map::before{content:""}.si-commenting::before{content:""}.si-commenting-o::before{content:""}.si-houzz::before{content:""}.si-vimeo::before{content:""}.si-black-tie::before{content:""}.si-fonticons::before{content:""}.si-lg{font-size:1.33333333em;line-height:0.75em;vertical-align:-15%}.si-2x{font-size:2em}.si-3x{font-size:3em}.si-4x{font-size:4em}.si-5x{font-size:5em}.si-fw{text-align:center;width:1.28571429em}.si-border{border-radius:.1em;padding:.2em .25em .15em;border:solid 0.08em}.si-pull-left{float:left;margin-right:.3em}.si-pull-right{float:right;margin-left:.3em}.si-rotate-90{-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);-o-transform:rotate(90deg);transform:rotate(90deg)}.si-rotate-180{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg)}.si-rotate-270{-webkit-transform:rotate(270deg);-moz-transform:rotate(270deg);-ms-transform:rotate(270deg);-o-transform:rotate(270deg);transform:rotate(270deg)}.si-flip-horizontal{-webkit-transform:scale(-1, 1);-moz-transform:scale(-1, 1);-ms-transform:scale(-1, 1);-o-transform:scale(-1, 1);transform:scale(-1, 1)}.si-flip-vertical{-webkit-transform:scale(1, -1);-moz-transform:scale(1, -1);-ms-transform:scale(1, -1);-o-transform:scale(1, -1);transform:scale(1, -1)}.si-inverse{-webkit-filter:invert(100%);filter:invert(100%)}.si-spin{-webkit-animation:si-animation-spin 2s infinite linear;-moz-animation:si-animation-spin 2s infinite linear;animation:si-animation-spin 2s infinite linear}.si-pulse{-webkit-animation:si-animation-spin 1s infinite steps(8);-moz-animation:si-animation-spin 1s infinite steps(8);animation:si-animation-spin 1s infinite steps(8)}.si-ul{padding-left:0;list-style-type:none;margin-left:2.14285714em}.si-ul>li{position:relative}.si-ul>li .si-li{text-align:center;position:absolute;left:-2.14285714em;width:2.14285714em;top:0.14285714em}.si-ul>li .si-li .si-lg{left:-1.85714286em}.si-stack{width:2em;height:2em;line-height:2em;vertical-align:middle;position:relative;display:inline-block}.si-stack .si-stack-1x,.si-stack .si-stack-2x{left:0;width:100%;text-align:center;position:absolute}.si-stack .si-stack-1x{line-height:inherit}.si-stack .si-stack-2x{font-size:2em}@-webkit-keyframes si-animation-spin{0%{-webkit-transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg)}}@-moz-keyframes si-animation-spin{0%{-moz-transform:rotate(0deg)}100%{-moz-transform:rotate(359deg)}}@keyframes si-animation-spin{0%{-webkit-transform:rotate(0deg);-moz-transform:rotate(0deg);-ms-transform:rotate(0deg);-o-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);-moz-transform:rotate(359deg);-ms-transform:rotate(359deg);-o-transform:rotate(359deg);transform:rotate(359deg)}}.plugin-menu-page-animation-spin{-webkit-animation-duration:0.75s;-moz-animation-duration:0.75s;animation-duration:0.75s;-webkit-animation-fill-mode:both;-moz-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation-timing-function:linear;-moz-animation-timing-function:linear;animation-timing-function:linear;-webkit-animation-iteration-count:infinite;-moz-animation-iteration-count:infinite;animation-iteration-count:infinite;-webkit-animation-name:plugin-menu-page-animation-spin;-moz-animation-name:plugin-menu-page-animation-spin;animation-name:plugin-menu-page-animation-spin}@-webkit-keyframes plugin-menu-page-animation-spin{0%{-webkit-transform:rotate(0deg)}100%{-webkit-transform:rotate(360deg)}}@-moz-keyframes plugin-menu-page-animation-spin{0%{-moz-transform:rotate(0deg)}100%{-moz-transform:rotate(360deg)}}@keyframes plugin-menu-page-animation-spin{0%{-webkit-transform:rotate(0deg);-moz-transform:rotate(0deg);-ms-transform:rotate(0deg);-o-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(360deg);-moz-transform:rotate(360deg);-ms-transform:rotate(360deg);-o-transform:rotate(360deg);transform:rotate(360deg)}}html{overflow-y:scroll}#wpwrap{position:relative}#wpwrap::after{top:0;right:0;bottom:0;left:0;z-index:-1;position:absolute;content:'';opacity:0.25;background:url("../images/bg.png")}#wpwrap .updated,#wpwrap .error{margin:1.25em 1.25em 1.25em 0.25em}.plugin-menu-page{min-width:800px;margin:1.25em 1.25em 1.25em 0.25em}.plugin-menu-page,.plugin-menu-page p{font-size:14px}.plugin-menu-page a{color:#033A63}.plugin-menu-page a:hover,.plugin-menu-page a:active{color:#467629}.plugin-menu-page p:first-child,.plugin-menu-page pre:first-child{margin-top:0}.plugin-menu-page p:last-child,.plugin-menu-page pre:last-child{margin-bottom:0}.plugin-menu-page code{border-radius:3px;padding:0.1em 0.25em;background:rgba(178,178,178,0.25);font-family:'Menlo', 'Monaco', 'Consolas', 'Courier New', monospace}.plugin-menu-page pre.code{padding:0;background:none}.plugin-menu-page pre.code>code{font-size:90%;overflow-x:auto;max-width:100%;border-radius:4px;padding:1em;display:block;color:#eee;background:#222;box-shadow:0 0 5px 1px #000 inset}.plugin-menu-page img{border:0}.plugin-menu-page img.screenshot{float:right;border-radius:4px;padding:0.5em;margin:0 0 2em 2em;background:#fff;border:1px solid #afafaf;box-shadow:0 0 5px 0 rgba(0,0,0,0.2) inset}.plugin-menu-page hr{border:0;padding:0;height:1px;margin:1em 0;background:linear-gradient(to left, transparent, rgba(0,0,0,0.75), transparent)}.plugin-menu-page label{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.plugin-menu-page label.switch-primary{font-size:130%;margin:0;padding:0.5em;border-radius:4px;display:inline;color:#000;background:#f1e982;border:1px solid rgba(0,0,0,0.07);box-shadow:-1px -1px 0 0 rgba(0,0,0,0.25) inset,1px 1px 0 0 #fff inset}.plugin-menu-page select,.plugin-menu-page textarea,.plugin-menu-page select:focus,.plugin-menu-page textarea:focus,.plugin-menu-page input:not([type='radio']):not([type='checkbox']),.plugin-menu-page input:not([type='radio']):not([type='checkbox']):focus{width:100%;line-height:1.3em;margin:0;padding:0.25em 0.5em;border-radius:4px;box-sizing:border-box;color:#333;background:#e8e8e8;border:1px solid #848484;box-shadow:0 0 2px 0 rgba(132,132,132,0.5) inset}.plugin-menu-page select,.plugin-menu-page select:focus{box-shadow:0 1px 0 0 #fff inset,0 -2px 3px 0 rgba(132,132,132,0.25) inset}.plugin-menu-page select,.plugin-menu-page select:focus,.plugin-menu-page input:not([type='radio']):not([type='checkbox']),.plugin-menu-page input:not([type='radio']):not([type='checkbox']):focus{height:2em}.plugin-menu-page select:focus,.plugin-menu-page textarea:focus,.plugin-menu-page input:not([type='radio']):not([type='checkbox']):focus{color:#000;background:#e2e2e2}.plugin-menu-page input[disabled],.plugin-menu-page select[disabled],.plugin-menu-page textarea[disabled]{opacity:0.5}.plugin-menu-page input::-webkit-input-placeholder,.plugin-menu-page textarea::-webkit-input-placeholder{font-style:italic;color:rgba(0,0,0,0.2)}.plugin-menu-page input::-moz-placeholder,.plugin-menu-page textarea::-moz-placeholder{font-style:italic;color:rgba(0,0,0,0.2)}.plugin-menu-page input:-moz-placeholder,.plugin-menu-page textarea:-moz-placeholder{font-style:italic;color:rgba(0,0,0,0.2)}.plugin-menu-page input:-ms-input-placeholder,.plugin-menu-page textarea:-ms-input-placeholder{font-style:italic;color:rgba(0,0,0,0.2)}.plugin-menu-page table{margin:1em 0}.plugin-menu-page button{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;font-size:150%;font-weight:bold;line-height:1em;outline:none;cursor:pointer;border-radius:4px;margin:0;padding:0.25em 0.5em;box-sizing:border-box;color:#fff;background:#033A63;border:1px solid rgba(0,0,0,0.5);box-shadow:0 1px 1px 0 rgba(0,0,0,0.25),-1px -1px 0 0 rgba(0,0,0,0.2) inset,1px 1px 0 0 rgba(255,255,255,0.1) inset}.plugin-menu-page button:hover{background:#467629}.plugin-menu-page button[type='submit']{background:#467629}.plugin-menu-page button[type='submit']:hover{background:#033A63}.plugin-menu-page button:active{-webkit-transform:scale(0.98, 0.98);-moz-transform:scale(0.98, 0.98);-ms-transform:scale(0.98, 0.98);-o-transform:scale(0.98, 0.98);transform:scale(0.98, 0.98)}.plugin-menu-page .info,.plugin-menu-page .notice,.plugin-menu-page .warning,.plugin-menu-page .error{border-radius:4px;padding:0.5em;margin:1em 0}.plugin-menu-page .info{background:#cadfed;border:1px solid #216095}.plugin-menu-page .notice{background:#fffde8;border:1px solid #e6db55}.plugin-menu-page .warning{background:#ffefd3;border:1px solid #e6db55}.plugin-menu-page .error{background:pink;border:1px solid #711e1e}.plugin-menu-page .monospace{font-family:'Menlo', 'Monaco', 'Consolas', 'Courier New', monospace}.plugin-menu-page textarea.monospace{white-space:pre}.plugin-menu-page .clearfix::before,.plugin-menu-page .clearfix::after{display:table;content:' '}.plugin-menu-page .clearfix::after{clear:both}.plugin-menu-page-heading .plugin-menu-page-restore-defaults,.plugin-menu-page-heading .plugin-menu-page-panel-togglers{float:right;margin:0 1em 0 0}.plugin-menu-page-heading .plugin-menu-page-panel-togglers button{background:#033A63 !important}.plugin-menu-page-heading .plugin-menu-page-upsells{float:right;clear:right;text-align:right;max-width:350px;margin:1em 0 0}.plugin-menu-page-heading .plugin-menu-page-upsells a{text-decoration:none;line-height:1.5em;margin:0 0.5em;display:inline-block}.plugin-menu-page-heading .plugin-menu-page-support-links,.plugin-menu-page-heading .plugin-menu-page-mailing-list-links{float:right;clear:right;text-align:right;max-width:400px;margin:.5em 0 0}.plugin-menu-page-heading .plugin-menu-page-support-links a,.plugin-menu-page-heading .plugin-menu-page-mailing-list-links a{text-decoration:none;margin:0 0.5em;display:inline-block}.plugin-menu-page-heading .plugin-menu-page-version{float:right;clear:right;min-width:350px;margin:0.5em 0 0 0;text-align:right}.plugin-menu-page-body{position:relative}.plugin-menu-page-section-heading{margin:1em 0}.plugin-menu-page-section-heading>small{font-size:65%;font-style:italic;margin:0;display:block;opacity:0.5}.plugin-menu-page-panel{margin:1em 0}.plugin-menu-page-panel:first-child{margin-top:0}.plugin-menu-page-panel .plugin-menu-page-panel-heading{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;text-decoration:none;padding:10px;font-size:150%;line-height:1.125em;font-weight:bold;border-radius:4px;display:block;cursor:pointer;background:#033A63;background:linear-gradient(to right, #033A63, #20669A);color:#eee !important;box-shadow:0 2px 2px 0 rgba(0,0,0,0.25)}.plugin-menu-page-panel .plugin-menu-page-panel-heading::after{font:normal normal normal 14px/1 sharkicons;text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased;font-smoothing:antialiased;display:inline-block;font-size:inherit;text-decoration:inherit;text-transform:none;content:""}.plugin-menu-page-panel .plugin-menu-page-panel-heading:hover,.plugin-menu-page-panel .plugin-menu-page-panel-heading.open{color:#fff !important}.plugin-menu-page-panel .plugin-menu-page-panel-heading::after{font-size:80%;float:right;margin:0 0 0 5px}.plugin-menu-page-panel .plugin-menu-page-panel-heading.open::after{content:""}.plugin-menu-page-panel-heading.pro-preview-feature{background:#216095}.pro-preview-feature::after{font-variant:small-caps !important;font-family:sans-serif !important;content:'pro version only' !important;margin-left:15px;background:#216095;color:#FFFFFF;padding:0 5px 2px 5px;font-weight:normal}.plugin-menu-page-panel-heading.pro-preview-additional-features{background:#216095}.pro-preview-additional-features::after{font-variant:small-caps !important;font-family:sans-serif !important;content:'additional pro features' !important;margin-left:15px;background:#216095;color:#FFFFFF;padding:0 5px 2px 5px;font-weight:normal}.plugin-menu-page-panel .plugin-menu-page-panel-heading>.si{text-align:center;width:1.28571429em;margin-right:.25em}.plugin-menu-page-panel .plugin-menu-page-panel-body{width:99%;margin:0 auto;display:none;padding:1.2em;border-bottom-left-radius:4px;border-bottom-right-radius:4px;box-sizing:border-box;color:#222;border:1px solid #848484;background:#fff;box-shadow:0 1px 1px 0 rgba(0,0,0,0.25),0 3px 1px -1px rgba(0,0,0,0.25) inset}.plugin-menu-page-panel .plugin-menu-page-panel-body.open{display:block}.plugin-menu-page-panel .plugin-menu-page-panel-body p{font-size:90%;color:#666}.plugin-menu-page-panel .plugin-menu-page-panel-body p.notice,.plugin-menu-page-panel .plugin-menu-page-panel-body p.info,.plugin-menu-page-panel .plugin-menu-page-panel-body p.warning,.plugin-menu-page-panel .plugin-menu-page-panel-body p.error{color:#000}.plugin-menu-page-panel .plugin-menu-page-panel-body h3{margin:0 0 0.5em}.plugin-menu-page-panel .plugin-menu-page-panel-body h3:first-child{margin-top:0}.plugin-menu-page-panel .plugin-menu-page-panel-body h3+p{margin-top:0}.plugin-menu-page-panel .plugin-menu-page-panel-body a.dotted{text-decoration:none;border-bottom:1px dotted}.plugin-menu-page-panel .plugin-menu-page-panel-body.pro-preview,.plugin-menu-page-panel .plugin-menu-page-panel-body .pro-preview{opacity:0.5}.plugin-menu-page-save{margin-top:2em}.plugin-menu-page-save button{line-height:1.3em;width:100%}.plugin-menu-page-save-and-update{margin-top:2em}.plugin-menu-page-save-and-update button{line-height:1.3em;display:inline;width:45%;margin-left:1.5em}
2
 
src/client-s/images/apache.png ADDED
Binary file
src/client-s/images/stats-preview.png ADDED
Binary file
src/client-s/js/menu-pages.js CHANGED
@@ -19,7 +19,7 @@
19
  $('[data-action]', plugin.$menuPage).on('click', plugin.doDataAction);
20
  $('[data-toggle-target]', plugin.$menuPage).on('click', plugin.doDataToggleTarget);
21
 
22
- $('select[name$="_enable\\]"]', plugin.$menuPage).not('.-no-if-enabled').on('change', plugin.enableDisable).trigger('change');
23
 
24
 
25
  };
@@ -58,7 +58,8 @@
58
  var $this = $(this),
59
  thisValue = $this.val(),
60
  thisName = $this.attr('name'),
61
- enabled = Number(thisValue) >= 1,
 
62
 
63
  $thisPanelBody = $this.closest('.plugin-menu-page-panel-body'),
64
 
19
  $('[data-action]', plugin.$menuPage).on('click', plugin.doDataAction);
20
  $('[data-toggle-target]', plugin.$menuPage).on('click', plugin.doDataToggleTarget);
21
 
22
+ $('select[name$="_enable\\]"], select[data-toggle~="enable-disable"]', plugin.$menuPage).not('.-no-if-enabled').on('change', plugin.enableDisable).trigger('change');
23
 
24
 
25
  };
58
  var $this = $(this),
59
  thisValue = $this.val(),
60
  thisName = $this.attr('name'),
61
+ thisEnabledStrings = String($this.data('enabledStrings') || '1,2,3,4,5').split(/,+/),
62
+ enabled = $.inArray(thisValue, thisEnabledStrings) !== -1,
63
 
64
  $thisPanelBody = $this.closest('.plugin-menu-page-panel-body'),
65
 
src/client-s/js/menu-pages.min.js CHANGED
@@ -1,7 +1,7 @@
1
  (function(b){var a={namespace:"comet_cache"},d=b(window),c=b(document);a.onReady=function(){
2
 
3
- ;a.$menuPage=b("#plugin-menu-page");a.vars=window[a.namespace+"_menu_page_vars"];b(".plugin-menu-page-panel-heading",a.$menuPage).on("click",a.togglePanel);b(".plugin-menu-page-panels-open",a.$menuPage).on("click",a.toggleAllPanelsOpen);b(".plugin-menu-page-panels-close",a.$menuPage).on("click",a.toggleAllPanelsClose);b("[data-action]",a.$menuPage).on("click",a.doDataAction);b("[data-toggle-target]",a.$menuPage).on("click",a.doDataToggleTarget);b('select[name$="_enable\\]"]',a.$menuPage).not(".-no-if-enabled").on("change",a.enableDisable).trigger("change");
4
 
5
- };a.toggleAllPanelsOpen=function(e){a.preventDefault(e);b(".plugin-menu-page-panel-heading",a.$menuPage).addClass("open").next(".plugin-menu-page-panel-body").addClass("open")};a.toggleAllPanelsClose=function(e){a.preventDefault(e);b(".plugin-menu-page-panel-heading",a.$menuPage).removeClass("open").next(".plugin-menu-page-panel-body").removeClass("open")};a.togglePanel=function(e){a.preventDefault(e);b(this).toggleClass("open").next(".plugin-menu-page-panel-body").toggleClass("open")};a.doDataAction=function(e){a.preventDefault(e);var g=b(this),f=g.data();if(typeof f.confirmation!=="string"||confirm(f.confirmation)){location.href=f.action}};a.enableDisable=function(e){var m=b(this),g=m.val(),f=m.attr("name"),l=Number(g)>=1,i=m.closest(".plugin-menu-page-panel-body"),n=m.data("target"),h=n?b(n,i).filter(".plugin-menu-page-panel-if-enabled"):null,k=m.closest(".plugin-menu-page-panel-if-enabled"),j=k.find("> .plugin-menu-page-panel-if-enabled"),o=i.find("> .plugin-menu-page-panel-if-enabled");if(l){if(n){h.css("opacity",1).find(":input").removeAttr("readonly")}else{if(k.length){j.css("opacity",1).find(":input").removeAttr("readonly")}else{o.css("opacity",1).find(":input").removeAttr("readonly")}}}else{if(n){h.css("opacity",0.4).find(":input").attr("readonly","readonly")}else{if(k.length){j.css("opacity",0.4).find(":input").attr("readonly","readonly")}else{o.css("opacity",0.4).find(":input").attr("readonly","readonly")}}}};a.doDataToggleTarget=function(f){a.preventDefault(f);var g=b(this),e=b(g.data("toggleTarget"));if(e.is(":visible")){e.hide();g.find(".si").removeClass("si-eye-slash").addClass("si-eye")}else{e.show();g.find(".si").removeClass("si-eye").addClass("si-eye-slash")}};a.handleCacheClearAdminBarOpsChange=function(g){var f=b(this),h=f.val(),e=b(".-clear-cache-ops-ss",a.$menuPage);e.attr("src",e.attr("src").replace(/ops[0-9]\-ss\.png$/,"ops"+h+"-ss.png"))};a.handleCdnHostsChange=function(f){var g=b(this),e=b('input[name$="[cdn_host]"]',a.$menuPage);if(b.trim(g.val())){if(e.val()){e.data("hiddenValue",e.val())}e.attr("disabled","disabled").val("")}else{if(!e.val()){e.val(e.data("hiddenValue"))}e.removeAttr("disabled");g.val("")}};
6
 
7
  ;a.bytesToSizeLabel=function(f,e){if(typeof f!=="number"||f<=1){return f===1?"1 byte":"0 bytes"}if(typeof e!=="number"||e<=0){e=0}var i=1024,j=Math.floor(Math.log(f)/Math.log(i)),h=["bytes","KB","MB","GB","TB","PB","EB","ZB","YB"],g=(f/Math.pow(i,j));return g.toFixed(e)+" "+h[j]};a.numberFormat=function(f,e){if(typeof f!=="number"){return String(f)}if(typeof e!=="number"||e<=0){e=0}return f.toFixed(e).replace(/./g,function(g,i,h){return i&&g!=="."&&((h.length-i)%3===0)?","+g:g})};a.escHtml=function(f){var e={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"};return String(f).replace(/[&<>"']/g,function(g){return e[g]})};a.preventDefault=function(f,e){if(!f){return}f.preventDefault();if(e){f.stopImmediatePropagation()}};c.ready(a.onReady)})(jQuery);
1
  (function(b){var a={namespace:"comet_cache"},d=b(window),c=b(document);a.onReady=function(){
2
 
3
+ ;a.$menuPage=b("#plugin-menu-page");a.vars=window[a.namespace+"_menu_page_vars"];b(".plugin-menu-page-panel-heading",a.$menuPage).on("click",a.togglePanel);b(".plugin-menu-page-panels-open",a.$menuPage).on("click",a.toggleAllPanelsOpen);b(".plugin-menu-page-panels-close",a.$menuPage).on("click",a.toggleAllPanelsClose);b("[data-action]",a.$menuPage).on("click",a.doDataAction);b("[data-toggle-target]",a.$menuPage).on("click",a.doDataToggleTarget);b('select[name$="_enable\\]"], select[data-toggle~="enable-disable"]',a.$menuPage).not(".-no-if-enabled").on("change",a.enableDisable).trigger("change");
4
 
5
+ };a.toggleAllPanelsOpen=function(e){a.preventDefault(e);b(".plugin-menu-page-panel-heading",a.$menuPage).addClass("open").next(".plugin-menu-page-panel-body").addClass("open")};a.toggleAllPanelsClose=function(e){a.preventDefault(e);b(".plugin-menu-page-panel-heading",a.$menuPage).removeClass("open").next(".plugin-menu-page-panel-body").removeClass("open")};a.togglePanel=function(e){a.preventDefault(e);b(this).toggleClass("open").next(".plugin-menu-page-panel-body").toggleClass("open")};a.doDataAction=function(e){a.preventDefault(e);var g=b(this),f=g.data();if(typeof f.confirmation!=="string"||confirm(f.confirmation)){location.href=f.action}};a.enableDisable=function(e){var m=b(this),g=m.val(),f=m.attr("name"),o=String(m.data("enabledStrings")||"1,2,3,4,5").split(/,+/),l=b.inArray(g,o)!==-1,i=m.closest(".plugin-menu-page-panel-body"),n=m.data("target"),h=n?b(n,i).filter(".plugin-menu-page-panel-if-enabled"):null,k=m.closest(".plugin-menu-page-panel-if-enabled"),j=k.find("> .plugin-menu-page-panel-if-enabled"),p=i.find("> .plugin-menu-page-panel-if-enabled");if(l){if(n){h.css("opacity",1).find(":input").removeAttr("readonly")}else{if(k.length){j.css("opacity",1).find(":input").removeAttr("readonly")}else{p.css("opacity",1).find(":input").removeAttr("readonly")}}}else{if(n){h.css("opacity",0.4).find(":input").attr("readonly","readonly")}else{if(k.length){j.css("opacity",0.4).find(":input").attr("readonly","readonly")}else{p.css("opacity",0.4).find(":input").attr("readonly","readonly")}}}};a.doDataToggleTarget=function(f){a.preventDefault(f);var g=b(this),e=b(g.data("toggleTarget"));if(e.is(":visible")){e.hide();g.find(".si").removeClass("si-eye-slash").addClass("si-eye")}else{e.show();g.find(".si").removeClass("si-eye").addClass("si-eye-slash")}};a.handleCacheClearAdminBarOpsChange=function(g){var f=b(this),h=f.val(),e=b(".-clear-cache-ops-ss",a.$menuPage);e.attr("src",e.attr("src").replace(/ops[0-9]\-ss\.png$/,"ops"+h+"-ss.png"))};a.handleCdnHostsChange=function(f){var g=b(this),e=b('input[name$="[cdn_host]"]',a.$menuPage);if(b.trim(g.val())){if(e.val()){e.data("hiddenValue",e.val())}e.attr("disabled","disabled").val("")}else{if(!e.val()){e.val(e.data("hiddenValue"))}e.removeAttr("disabled");g.val("")}};
6
 
7
  ;a.bytesToSizeLabel=function(f,e){if(typeof f!=="number"||f<=1){return f===1?"1 byte":"0 bytes"}if(typeof e!=="number"||e<=0){e=0}var i=1024,j=Math.floor(Math.log(f)/Math.log(i)),h=["bytes","KB","MB","GB","TB","PB","EB","ZB","YB"],g=(f/Math.pow(i,j));return g.toFixed(e)+" "+h[j]};a.numberFormat=function(f,e){if(typeof f!=="number"){return String(f)}if(typeof e!=="number"||e<=0){e=0}return f.toFixed(e).replace(/./g,function(g,i,h){return i&&g!=="."&&((h.length-i)%3===0)?","+g:g})};a.escHtml=function(f){var e={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"};return String(f).replace(/[&<>"']/g,function(g){return e[g]})};a.preventDefault=function(f,e){if(!f){return}f.preventDefault();if(e){f.stopImmediatePropagation()}};c.ready(a.onReady)})(jQuery);
src/includes/classes/Actions.php CHANGED
@@ -160,6 +160,7 @@ class Actions extends AbsBase
160
  unset($args['last_pro_update_check']); // CANNOT be imported!
161
  unset($args['last_pro_stats_log']); // CANNOT be imported!
162
  }
 
163
  $args = $this->plugin->trimDeep(stripslashes_deep((array) $args));
164
  $this->plugin->updateOptions($args); // Save/update options.
165
 
@@ -187,7 +188,7 @@ class Actions extends AbsBase
187
  $query_args[GLOBAL_NS.'_advanced_cache_add_failure'] = $add_advanced_cache === null ? 'advanced-cache' : '1';
188
  }
189
  if (!$this->plugin->options['auto_cache_enable']) {
190
- $this->plugin->dismissMainNotice('allow_url_fopen_disabled'); // Dismiss and check again on `admin_init` via `autoCacheMaybeClearPhpIniError()`
191
  }
192
  if (!$this->plugin->options['auto_cache_enable'] || !$this->plugin->options['auto_cache_sitemap_url']) {
193
  $this->plugin->dismissMainNotice('xml_sitemap_missing'); // Dismiss and check again on `admin_init` via `autoCacheMaybeClearPrimaryXmlSitemapError()`
@@ -204,7 +205,7 @@ class Actions extends AbsBase
204
  $query_args[GLOBAL_NS.'_advanced_cache_remove_failure'] = '1';
205
  }
206
  $this->plugin->dismissMainNotice('xml_sitemap_missing'); // Dismiss notice when disabling plugin
207
- $this->plugin->dismissMainNotice('allow_url_fopen_disabled'); // Dismiss notice when disabling plugin
208
  }
209
  $redirect_to = add_query_arg(urlencode_deep($query_args), $redirect_to);
210
 
160
  unset($args['last_pro_update_check']); // CANNOT be imported!
161
  unset($args['last_pro_stats_log']); // CANNOT be imported!
162
  }
163
+
164
  $args = $this->plugin->trimDeep(stripslashes_deep((array) $args));
165
  $this->plugin->updateOptions($args); // Save/update options.
166
 
188
  $query_args[GLOBAL_NS.'_advanced_cache_add_failure'] = $add_advanced_cache === null ? 'advanced-cache' : '1';
189
  }
190
  if (!$this->plugin->options['auto_cache_enable']) {
191
+ $this->plugin->dismissMainNotice('auto_cache_engine_minimum_requirements'); // Dismiss and check again on `admin_init` via `autoCacheMaybeClearPhpReqsError()`
192
  }
193
  if (!$this->plugin->options['auto_cache_enable'] || !$this->plugin->options['auto_cache_sitemap_url']) {
194
  $this->plugin->dismissMainNotice('xml_sitemap_missing'); // Dismiss and check again on `admin_init` via `autoCacheMaybeClearPrimaryXmlSitemapError()`
205
  $query_args[GLOBAL_NS.'_advanced_cache_remove_failure'] = '1';
206
  }
207
  $this->plugin->dismissMainNotice('xml_sitemap_missing'); // Dismiss notice when disabling plugin
208
+ $this->plugin->dismissMainNotice('auto_cache_engine_minimum_requirements'); // Dismiss notice when disabling plugin
209
  }
210
  $redirect_to = add_query_arg(urlencode_deep($query_args), $redirect_to);
211
 
src/includes/classes/AdvCacheBackCompat.php CHANGED
@@ -44,16 +44,16 @@ class AdvCacheBackCompat
44
  */
45
  public static function zenCacheConstants()
46
  {
47
- $_global_ns = strtoupper(GLOBAL_NS);
48
 
49
  if (!($constants = get_defined_constants(true)) || empty($constants['user'])) {
50
  return; // Nothing to do; i.e. no user-defined constants.
51
  }
52
  foreach ($constants['user'] as $_constant => $_value) {
53
- if (stripos($_constant, 'ZENCACHE_') !== 0) {
54
  continue; // Nothing to do here.
55
  }
56
- if (!($_constant_sub_name = substr($_constant, 9))) {
57
  continue; // Nothing to do here.
58
  }
59
  if (!defined($_global_ns.'_'.$_constant_sub_name)) {
@@ -66,4 +66,18 @@ class AdvCacheBackCompat
66
 
67
  unset($_constant, $_value, $_global_ns); // Housekeeping.
68
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
69
  }
44
  */
45
  public static function zenCacheConstants()
46
  {
47
+ $_global_ns = mb_strtoupper(GLOBAL_NS);
48
 
49
  if (!($constants = get_defined_constants(true)) || empty($constants['user'])) {
50
  return; // Nothing to do; i.e. no user-defined constants.
51
  }
52
  foreach ($constants['user'] as $_constant => $_value) {
53
+ if (mb_stripos($_constant, 'ZENCACHE_') !== 0) {
54
  continue; // Nothing to do here.
55
  }
56
+ if (!($_constant_sub_name = mb_substr($_constant, 9))) {
57
  continue; // Nothing to do here.
58
  }
59
  if (!defined($_global_ns.'_'.$_constant_sub_name)) {
66
 
67
  unset($_constant, $_value, $_global_ns); // Housekeeping.
68
  }
69
+
70
+ /**
71
+ * Back compat. with `COMET_CACHE_ALLOW_BROWSER_CACHE` constants.
72
+ *
73
+ * @since 160706 Renaming COMET_CACHE_ALLOW_BROWSER_CACHE to COMET_CACHE_ALLOW_CLIENT_SIDE_CACHE
74
+ */
75
+ public static function browserCacheConstant()
76
+ {
77
+ $_global_ns = mb_strtoupper(GLOBAL_NS);
78
+
79
+ if (defined('COMET_CACHE_ALLOW_BROWSER_CACHE')) {
80
+ define($_global_ns.'_ALLOW_CLIENT_SIDE_CACHE', COMET_CACHE_ALLOW_BROWSER_CACHE);
81
+ }
82
+ }
83
  }
src/includes/classes/AdvancedCache.php CHANGED
@@ -13,7 +13,7 @@ class AdvancedCache extends AbsBaseAp
13
  /*[.build.php-auto-generate-use-Traits]*/
14
  use Traits\Ac\AbortUtils;
15
  use Traits\Ac\AcPluginUtils;
16
- use Traits\Ac\BrowserUtils;
17
  use Traits\Ac\NcDebugUtils;
18
  use Traits\Ac\ObUtils;
19
  use Traits\Ac\PostloadUtils;
13
  /*[.build.php-auto-generate-use-Traits]*/
14
  use Traits\Ac\AbortUtils;
15
  use Traits\Ac\AcPluginUtils;
16
+ use Traits\Ac\ClientSideUtils;
17
  use Traits\Ac\NcDebugUtils;
18
  use Traits\Ac\ObUtils;
19
  use Traits\Ac\PostloadUtils;
src/includes/classes/Conflicts.php CHANGED
@@ -77,9 +77,9 @@ class Conflicts
77
  return; // Already did this in one plugin or the other.
78
  }
79
  $construct_name = function ($slug_or_ns) {
80
- $name = trim(strtolower((string) $slug_or_ns));
81
- $name = preg_replace('/[_\-]+(?:lite|pro)$/', '', $name);
82
- $name = preg_replace('/[^a-z0-9]/', ' ', $name);
83
  $name = str_replace('cache', 'Cache', ucwords($name));
84
 
85
  return $name; // e.g., `x-cache` becomes `X Cache`.
77
  return; // Already did this in one plugin or the other.
78
  }
79
  $construct_name = function ($slug_or_ns) {
80
+ $name = trim(mb_strtolower((string) $slug_or_ns));
81
+ $name = preg_replace('/[_\-]+(?:lite|pro)$/u', '', $name);
82
+ $name = preg_replace('/[^a-z0-9]/u', ' ', $name);
83
  $name = str_replace('cache', 'Cache', ucwords($name));
84
 
85
  return $name; // e.g., `x-cache` becomes `X Cache`.
src/includes/classes/FeedUtils.php CHANGED
@@ -174,14 +174,14 @@ class FeedUtils extends AbsBase
174
  $_term_feed_link = get_term_feed_link($_post_term->term_id, $_post_term->taxonomy, $_feed_type);
175
  $variations[] = $_term_feed_link; // Add this variation; always.
176
 
177
- if ($include_regex_wildcard_keys && $_term_feed_link && strpos($_term_feed_link, '?') === false) {
178
  // Quick example: `(?:123|slug)`; to consider both of these variations.
179
  $_term_id_or_slug = '(?:'.preg_quote($_post_term->term_id, '/').
180
- '|'.preg_quote(preg_replace('/[^a-z0-9\/.]/i', '-', $_post_term->slug), '/').')';
181
 
182
  // Quick example: `http://www.example.com/tax/term/feed`;
183
  // with a wildcard this becomes: `http://www.example.com/tax/*/feed`.
184
- $_term_feed_link_with_wildcard = preg_replace('/\/[^\/]+\/feed([\/?#]|$)/', '/*/feed'.'${1}', $_term_feed_link);
185
 
186
  // Quick example: `http://www.example.com/tax/*/feed`;
187
  // becomes: `\/http\/www\.example\.com\/tax\/.*?(?=[\/\-]?(?:123|slug)[\/\-]).*?\/feed`
@@ -250,14 +250,14 @@ class FeedUtils extends AbsBase
250
  $_host_url = rtrim('http://'.$_url_parts['host'].$_host_base_dir_tokens, '/');
251
  $_host_cache_path = $this->plugin->buildCachePath($_host_url, '', '', $flags);
252
 
253
- if (is_string($_key) && strpos($_key, '::') !== false && strpos($_url, '*') !== false) {
254
  list($_feed_type, $_wildcard_regex) = explode('::', $_key, 2); // This regex replaces wildcards.
255
  $_cache_path = $this->plugin->buildCachePath($_url, '', '', $flags | $this::CACHE_PATH_ALLOW_WILDCARDS);
256
- $_relative_cache_path = preg_replace('/^'.preg_quote($_host_cache_path, '/').'(?:\/|$)/i', '', $_cache_path);
257
- $_relative_cache_path_regex = preg_replace('/\\\\\*/', $_wildcard_regex, preg_quote($_relative_cache_path, '/'));
258
  } else {
259
  $_cache_path = $this->plugin->buildCachePath($_url, '', '', $flags); // Default flags.
260
- $_relative_cache_path = preg_replace('/^'.preg_quote($_host_cache_path, '/').'(?:\/|$)/i', '', $_cache_path);
261
  $_relative_cache_path_regex = preg_quote($_relative_cache_path, '/');
262
  }
263
  if ($_relative_cache_path_regex) {
174
  $_term_feed_link = get_term_feed_link($_post_term->term_id, $_post_term->taxonomy, $_feed_type);
175
  $variations[] = $_term_feed_link; // Add this variation; always.
176
 
177
+ if ($include_regex_wildcard_keys && $_term_feed_link && mb_strpos($_term_feed_link, '?') === false) {
178
  // Quick example: `(?:123|slug)`; to consider both of these variations.
179
  $_term_id_or_slug = '(?:'.preg_quote($_post_term->term_id, '/').
180
+ '|'.preg_quote(preg_replace('/[^a-z0-9\/.]/ui', '-', $_post_term->slug), '/').')';
181
 
182
  // Quick example: `http://www.example.com/tax/term/feed`;
183
  // with a wildcard this becomes: `http://www.example.com/tax/*/feed`.
184
+ $_term_feed_link_with_wildcard = preg_replace('/\/[^\/]+\/feed([\/?#]|$)/u', '/*/feed'.'${1}', $_term_feed_link);
185
 
186
  // Quick example: `http://www.example.com/tax/*/feed`;
187
  // becomes: `\/http\/www\.example\.com\/tax\/.*?(?=[\/\-]?(?:123|slug)[\/\-]).*?\/feed`
250
  $_host_url = rtrim('http://'.$_url_parts['host'].$_host_base_dir_tokens, '/');
251
  $_host_cache_path = $this->plugin->buildCachePath($_host_url, '', '', $flags);
252
 
253
+ if (is_string($_key) && mb_strpos($_key, '::') !== false && mb_strpos($_url, '*') !== false) {
254
  list($_feed_type, $_wildcard_regex) = explode('::', $_key, 2); // This regex replaces wildcards.
255
  $_cache_path = $this->plugin->buildCachePath($_url, '', '', $flags | $this::CACHE_PATH_ALLOW_WILDCARDS);
256
+ $_relative_cache_path = preg_replace('/^'.preg_quote($_host_cache_path, '/').'(?:\/|$)/ui', '', $_cache_path);
257
+ $_relative_cache_path_regex = preg_replace('/\\\\\*/u', $_wildcard_regex, preg_quote($_relative_cache_path, '/'));
258
  } else {
259
  $_cache_path = $this->plugin->buildCachePath($_url, '', '', $flags); // Default flags.
260
+ $_relative_cache_path = preg_replace('/^'.preg_quote($_host_cache_path, '/').'(?:\/|$)/ui', '', $_cache_path);
261
  $_relative_cache_path_regex = preg_quote($_relative_cache_path, '/');
262
  }
263
  if ($_relative_cache_path_regex) {
src/includes/classes/MenuPageOptions.php CHANGED
@@ -18,6 +18,7 @@ class MenuPageOptions extends MenuPage
18
  parent::__construct(); // Parent constructor.
19
 
20
  global $is_nginx; // WP global for web server checks below.
 
21
 
22
  echo '<form id="plugin-menu-page" class="plugin-menu-page" method="post" enctype="multipart/form-data"'.
23
  ' action="'.esc_attr(add_query_arg(urlencode_deep(['page' => GLOBAL_NS, '_wpnonce' => wp_create_nonce()]), self_admin_url('/admin.php'))).'">'."\n";
@@ -68,12 +69,16 @@ class MenuPageOptions extends MenuPage
68
  echo ' <a href="'.esc_attr('http://cometcache.com/blog/').'" target="_blank"><i class="si si-rss-square"></i> '.__('Blog', 'comet-cache').'</a>'."\n";
69
  echo ' </div>'."\n";
70
 
 
 
71
  if (!IS_PRO) { // We show these above in the Pro version
72
- echo ' <div class="plugin-menu-page-mailing-list-links">'."\n";
73
  echo ' <a href="'.esc_attr('http://cometcache.com/r/comet-cache-subscribe/').'" target="_blank"><i class="si si-envelope"></i> '.__('Newsletter', 'comet-cache').'</a>'."\n";
74
  echo ' <a href="'.esc_attr('http://cometcache.com/r/comet-cache-beta-testers-list/').'" target="_blank"><i class="si si-envelope"></i> '.__('Beta Testers', 'comet-cache').'</a>'."\n";
75
- echo ' </div>'."\n";
76
  }
 
 
 
 
77
 
78
  if (IS_PRO) {
79
  echo '<div class="plugin-menu-page-version">'."\n";
@@ -149,7 +154,7 @@ class MenuPageOptions extends MenuPage
149
  }
150
  if (!empty($_REQUEST[GLOBAL_NS.'_wp_config_wp_cache_add_failure'])) {
151
  echo '<div class="plugin-menu-page-notice error">'."\n";
152
- echo ' <i class="si si-thumbs-down"></i> '.__('Failed to update your <code>/wp-config.php</code> file automatically. Please add the following line to your <code>/wp-config.php</code> file (right after the opening <code>&lt;?php</code> tag; on it\'s own line). <pre class="code"><code>&lt;?php<br />define(\'WP_CACHE\', TRUE);</code></pre>', 'comet-cache')."\n";
153
  echo '</div>'."\n";
154
  }
155
  if (!empty($_REQUEST[GLOBAL_NS.'_wp_config_wp_cache_remove_failure'])) {
@@ -160,7 +165,7 @@ class MenuPageOptions extends MenuPage
160
  if (!empty($_REQUEST[GLOBAL_NS.'_advanced_cache_add_failure'])) {
161
  echo '<div class="plugin-menu-page-notice error">'."\n";
162
  if ($_REQUEST[GLOBAL_NS.'_advanced_cache_add_failure'] === 'advanced-cache') {
163
- echo '<i class="si si-thumbs-down"></i> '.sprintf(__('Failed to update your <code>/wp-content/advanced-cache.php</code> file. Cannot write stat file: <code>%1$s/%2$s-advanced-cache</code>. Please be sure this directory exists (and that it\'s writable): <code>%1$s</code>. Please use directory permissions <code>755</code> or higher (perhaps <code>777</code>). Once you\'ve done this, please try again.', 'comet-cache'), esc_html($this->plugin->cacheDir()), esc_html(strtolower(SHORT_NAME)))."\n";
164
  } else {
165
  echo '<i class="si si-thumbs-down"></i> '.__('Failed to update your <code>/wp-content/advanced-cache.php</code> file. Most likely a permissions error. Please create an empty file here: <code>/wp-content/advanced-cache.php</code> (just an empty PHP file, with nothing in it); give it permissions <code>644</code> or higher (perhaps <code>666</code>). Once you\'ve done this, please try again.', 'comet-cache')."\n";
166
  }
@@ -429,9 +434,10 @@ class MenuPageOptions extends MenuPage
429
  if (IS_PRO || $this->plugin->isProPreview()) {
430
  echo ' <hr />'."\n";
431
  echo ' <h3 class="'.(!IS_PRO ? 'pro-preview-feature' : '').'">'.__('Misc. Auto-Clear Options', 'comet-cache').'</h3>'."\n";
432
- echo '<h4 style="margin-bottom:0;">'.__('Auto-Clear a List of Custom URLs Too?', 'comet-cache').'</h4>'."\n";
433
- echo '<p style="margin-top:2px;">'.sprintf(__('When you update a Post/Page, approve a Comment, or make other changes where %1$s can detect that a Post/Page cache should be cleared to keep your site up-to-date; then %1$s will also clear a list of custom URLs that you list here. <strong>Please list one URL per line.</strong> A wildcard <code>*</code> character can also be used when necessary; e.g., <code>/category/abc-followed-by-*</code> (where <code>*</code> = 0 or more characters that are NOT a slash <code>/</code>). Other special characters include: <code>**</code> = 0 or more characters of any kind, including <code>/</code> slashes; <code>^</code> = beginning of the string; <code>$</code> = end of the string. To learn more about this syntax, please see <a href ="http://cometcache.com/r/watered-down-regex-syntax/" target="_blank">this KB article</a>.', 'comet-cache'), esc_html(NAME)).'</p>'."\n";
434
- echo '<p><textarea name="'.esc_attr(GLOBAL_NS).'[saveOptions][cache_clear_urls]" spellcheck="false" wrap="off" rows="5">'.format_to_edit($this->plugin->options['cache_clear_urls']).'</textarea></p>'."\n";
 
435
  }
436
  echo ' </div>'."\n";
437
 
@@ -447,6 +453,9 @@ class MenuPageOptions extends MenuPage
447
  echo ' </a>'."\n";
448
 
449
  echo ' <div class="plugin-menu-page-panel-body clearfix">'."\n";
 
 
 
450
  echo ' <i class="si si-pie-chart si-4x" style="float:right; margin: 0 0 0 25px;"></i>'."\n";
451
  echo ' <h3>'.__('Enable Cache-Related Stats &amp; Charts?', 'comet-cache').'</h3>'."\n";
452
  echo ' <p>'.sprintf(__('%1$s can collect and display cache-related statistics (including charts). Stats are displayed in the WordPress Admin Bar, and also in your Dashboard under: <strong>%1$s → Stats/Charts</strong>. Cache-related stats provide you with a quick look at what\'s happening behind-the-scenes. Your site grows faster and faster as the cache grows larger in size.', 'comet-cache'), esc_html(NAME)).'</p>'."\n";
@@ -538,9 +547,9 @@ class MenuPageOptions extends MenuPage
538
  echo ' <p style="'.($_sys_getloadavg_unavailable ? 'opacity: 0.5;' : '').'">'.sprintf(__('If you have high traffic at certain times of the day, %1$s can be told to check the current load average via <a href="http://cometcache.com/r/system-load-average-via-php/" target="_blank"><code>sys_getloadavg()</code></a>. If your server\'s load average has been high in the last 15 minutes or so, cache expiration is disabled automatically to help reduce stress on the server; i.e., to avoid generating a new version of the cache while the server is very busy.', 'comet-cache'), esc_html(NAME)).'</p>'."\n";
539
  echo ' <p style="'.($_sys_getloadavg_unavailable ? 'opacity: 0.5;' : '').'">'.sprintf(__('To enable this functionality you should first determine what a high load average is for your server. If you log into your machine via SSH you can run the <code>top</code> command to get a feel for what a high load average looks like. Once you know the number, you can enter it in the field below; e.g., <code>1.05</code> might be a high load average for a server with one CPU. See also: <a href="http://cometcache.com/r/understanding-load-average/" target="_blank">Understanding Load Average</a>', 'comet-cache'), esc_html(NAME)).'</p>'."\n";
540
  echo ' <p><input '.($_sys_getloadavg_unavailable ? 'disabled' : '').' type="text" name="'.esc_attr(GLOBAL_NS).'[saveOptions][cache_max_age_disable_if_load_average_is_gte]" value="'.esc_attr($this->plugin->options['cache_max_age_disable_if_load_average_is_gte']).'" /></p>'."\n";
541
- if ($_sys_getloadavg_unavailable && stripos(PHP_OS, 'win') === 0) { // See: <http://jas.xyz/1HZsZ9v>
542
  echo ' <p class="warning">'.__('<strong>Note:</strong> It appears that your server is running Windows. The <code>sys_getloadavg()</code> function has not been implemented in PHP for Windows servers yet.', 'comet-cache').'</p>'."\n";
543
- } elseif ($_sys_getloadavg_unavailable && stripos(PHP_OS, 'win') !== 0) {
544
  echo ' <p class="warning">'.__('<strong>Note:</strong> <code>sys_getloadavg()</code> has been disabled by your web hosting company or is not available on your server.', 'comet-cache').'</p>'."\n";
545
  }
546
  echo ' </div>'."\n";
@@ -561,20 +570,24 @@ class MenuPageOptions extends MenuPage
561
  echo ' <i class="si si-desktop si-4x" style="float:right; margin: 0 0 0 25px;"></i>'."\n";
562
  echo ' <h3>'.__('Allow Double-Caching In The Client-Side Browser?', 'comet-cache').'</h3>'."\n";
563
  echo ' <p>'.__('Recommended setting: <code>No</code> (for membership sites, very important). Otherwise, <code>Yes</code> would be better (if users do NOT log in/out of your site).', 'comet-cache').'</p>'."\n";
 
564
  echo ' <p>'.sprintf(__('%1$s handles content delivery through its ability to communicate with a browser using PHP. If you allow a browser to (cache) the caching system itself, you are momentarily losing some control; and this can have a negative impact on users that see more than one version of your site; e.g., one version while logged-in, and another while NOT logged-in. For instance, a user may log out of your site, but upon logging out they report seeing pages on the site which indicate they are STILL logged in (even though they\'re not — that\'s bad). This can happen if you allow a client-side cache, because their browser may cache web pages they visited while logged into your site which persist even after logging out. Sending no-cache headers will work to prevent this issue.', 'comet-cache'), esc_html(NAME)).'</p>'."\n";
565
  echo ' <p>'.__('All of that being said, if all you care about is blazing fast speed and users don\'t log in/out of your site (only you do); you can safely set this to <code>Yes</code> (recommended in this case). Allowing a client-side browser cache will improve speed and reduce outgoing bandwidth when this option is feasible.', 'comet-cache').'</p>'."\n";
566
- echo ' <p><select name="'.esc_attr(GLOBAL_NS).'[saveOptions][allow_browser_cache]">'."\n";
567
- echo ' <option value="0"'.selected($this->plugin->options['allow_browser_cache'], '0', false).'>'.__('No, prevent a client-side browser cache (safest option).', 'comet-cache').'</option>'."\n";
568
- echo ' <option value="1"'.selected($this->plugin->options['allow_browser_cache'], '1', false).'>'.__('Yes, I will allow a client-side browser cache of pages on the site.', 'comet-cache').'</option>'."\n";
569
  echo ' </select></p>'."\n";
570
  echo ' <p class="info">'.__('<strong>Tip:</strong> Setting this to <code>No</code> is highly recommended when running a membership plugin like <a href="http://wordpress.org/plugins/s2member/" target="_blank">s2Member</a> (as one example). In fact, many plugins like s2Member will send <a href="http://codex.wordpress.org/Function_Reference/nocache_headers" target="_blank">nocache_headers()</a> on their own, so your configuration here will likely be overwritten when you run such plugins (which is better anyway). In short, if you run a membership plugin, you should NOT allow a client-side browser cache.', 'comet-cache').'</p>'."\n";
571
  echo ' <p class="info">'.__('<strong>Tip:</strong> Setting this to <code>No</code> will NOT impact static content; e.g., CSS, JS, images, or other media. This setting pertains only to dynamic PHP scripts which produce content generated by WordPress.', 'comet-cache').'</p>'."\n";
572
- echo ' <p class="info">'.sprintf(__('<strong>Advanced Tip:</strong> if you have this set to <code>No</code>, but you DO want to allow a few special URLs to be cached by the browser; you can add this parameter to your URL <code>?%2$sABC=1</code>. This tells %1$s that it\'s OK for the browser to cache that particular URL. In other words, the <code>%2$sABC=1</code> parameter tells %1$s NOT to send no-cache headers to the browser.', 'comet-cache'), esc_html(NAME), esc_html(strtolower(SHORT_NAME))).'</p>'."\n";
573
- echo ' <h3>'.__('Exclusion Patterns for Client-Side Caching', 'comet-cache').'</h3>'."\n";
574
- echo ' <p>'.__('When you enable Client-Side Caching above, you may want to prevent certain pages on your site from being cached by a client-side browser. This is where you will enter those if you need to (one per line). Searches are performed against the <a href="https://gist.github.com/jaswsinc/338b6eb03a36c048c26f" target="_blank" style="text-decoration:none;"><code>REQUEST_URI</code></a>; i.e., <code>/path/?query</code> (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 <code>*</code> character can also be used when necessary; e.g., <code>/category/abc-followed-by-*</code> (where <code>*</code> = 0 or more characters that are NOT a slash <code>/</code>). Other special characters include: <code>**</code> = 0 or more characters of any kind, including <code>/</code> slashes; <code>^</code> = beginning of the string; <code>$</code> = end of the string. To learn more about this syntax, please see <a href ="http://cometcache.com/r/watered-down-regex-syntax/" target="_blank">this KB article</a>.', 'comet-cache').'</p>'."\n";
575
- echo ' <p><textarea name="'.esc_attr(GLOBAL_NS).'[saveOptions][exclude_client_side_uris]" rows="5" spellcheck="false" class="monospace">'.format_to_edit($this->plugin->options['exclude_client_side_uris']).'</textarea></p>'."\n";
576
- echo ' <p class="info">'.__('<strong>Tip:</strong> let\'s use this example URL: <code>http://www.example.com/post/example-post-123</code>. To exclude this URL, you would put this line into the field above: <code>/post/example-post-123</code>. Or, you could also just put in a small fragment, like: <code>example</code> or <code>example-*-123</code> and that would exclude any URI containing that word fragment.', 'comet-cache').'</p>'."\n";
577
- echo ' <p class="info">'.__('<strong>Note:</strong> please remember that your entries here should be formatted as a line-delimited list; e.g., one exclusion pattern per line.', 'comet-cache').'</p>'."\n";
 
 
 
578
  echo ' </div>'."\n";
579
 
580
  echo '</div>'."\n";
@@ -594,9 +607,9 @@ class MenuPageOptions extends MenuPage
594
  echo ' <p>'.__('This should almost ALWAYS be set to <code>No</code>. Most sites will NOT want to cache content generated while a user is logged-in. Doing so could result in a cache of dynamic content generated specifically for a particular user, where the content being cached may contain details that pertain only to the user that was logged-in when the cache was generated. Imagine visiting a website that says you\'re logged-in as Billy Bob (but you\'re not Billy Bob; NOT good). In short, do NOT turn this on unless you know what you\'re doing.', 'comet-cache').'</p>'."\n";
595
  echo ' <i class="si si-sitemap si-4x" style="float:right; margin: 0 0 0 25px;"></i>'."\n";
596
  echo ' <p>'.sprintf(__('<strong>Exception (Membership Sites):</strong> If you run a site with many users and the majority of your traffic comes from users who ARE logged-in, please choose: <code>Yes (maintain separate cache)</code>. %1$s will operate normally; but when a user is logged-in, the cache is user-specific. %1$s will intelligently refresh the cache when/if a user submits a form on your site with the GET or POST method. Or, if you make changes to their account (or another plugin makes changes to their account); including user <a href="http://codex.wordpress.org/Function_Reference/update_user_option" target="_blank">option</a>|<a href="http://codex.wordpress.org/Function_Reference/update_user_meta" target="_blank">meta</a> additions, updates &amp; deletions too. However, please note that enabling this feature (e.g., user-specific cache entries); will eat up MUCH more disk space. That being said, the benefits of this feature for most sites will outweigh the disk overhead (e.g., it\'s NOT an issue in most cases). Unless you are short on disk space (or you have MANY thousands of users), the disk overhead is neglible.', 'comet-cache'), esc_html(NAME)).'</p>'."\n";
597
- echo ' <p><select name="'.esc_attr(GLOBAL_NS).'[saveOptions][when_logged_in]">'."\n";
598
- echo ' <option value="0"'.selected($this->plugin->options['when_logged_in'], '0', false).'>'.__('No, do NOT cache; or serve a cache file when a user is logged-in (safest option).', 'comet-cache').'</option>'."\n";
599
- echo ' <option value="postload"'.selected($this->plugin->options['when_logged_in'], 'postload', false).'>'.__('Yes, and maintain a separate cache for each user (recommended for membership sites).', 'comet-cache').'</option>'."\n";
600
  if ($this->plugin->options['when_logged_in'] === '1' || get_site_option(GLOBAL_NS.'_when_logged_in_was_1')) {
601
  update_site_option(GLOBAL_NS.'_when_logged_in_was_1', '1');
602
  echo ' <option value="1"'.selected($this->plugin->options['when_logged_in'], '1', false).'>'.__('Yes, but DON\'T maintain a separate cache for each user (I know what I\'m doing).', 'comet-cache').'</option>'."\n";
@@ -608,22 +621,30 @@ class MenuPageOptions extends MenuPage
608
  echo ' <p class="info">'.__('<strong>Note:</strong> For most sites, the majority of their traffic (if not all of their traffic) comes from visitors who are not logged in, so disabling the cache for logged-in users is NOT ordinarily a performance issue. When a user IS logged-in, disabling the cache is considered ideal, because a logged-in user has a session open with your site; and the content they view should remain very dynamic in this scenario.', 'comet-cache').'</p>'."\n";
609
  echo ' <p class="info">'.sprintf(__('<strong>Note:</strong> This setting includes some users who AREN\'T actually logged into the system, but who HAVE authored comments recently. %1$s includes comment authors as part of it\'s logged-in user check. This way comment authors will be able to see updates to the comment thread immediately; and, so that any dynamically-generated messages displayed by your theme will work as intended. In short, %1$s thinks of a comment author as a logged-in user, even though technically they are not. ~ Users who gain access to password-protected Posts/Pages are also included.', 'comet-cache'), esc_html(NAME)).'</p>'."\n";
610
  echo ' <hr />'."\n";
611
- echo ' <h3>'.__('Static CDN Filters Enabled for Logged-In Users &amp; Comment Authors?', 'comet-cache').'</h3>'."\n";
612
- echo ' <p>'.__('While this defaults to a value of <code>No</code>, it should almost always be set to <code>Yes</code>. This value defaults to <code>No</code> only because Logged-In User caching (see above) defaults to <code>No</code> and setting this value to <code>Yes</code> by default can cause confusion for some users. Once you understand that Static CDN Filters can be applied safely for all visitors (logged-in or not logged-in), please choose <code>Yes</code> in the dropdown below. If you are not using Static CDN Filters, the value below is ignored.', 'comet-cache').'</p>'."\n";
613
- echo ' <p><select name="'.esc_attr(GLOBAL_NS).'[saveOptions][cdn_when_logged_in]">'."\n";
614
- echo ' <option value="0"'.selected($this->plugin->options['cdn_when_logged_in'], '0', false).'>'.__('No, disable Static CDN Filters when a user is logged-in.', 'comet-cache').'</option>'."\n";
615
- echo ' <option value="postload"'.selected($this->plugin->options['cdn_when_logged_in'], 'postload', false).'>'.__('Yes, enable Static CDN Filters for logged-in users (recommended) .', 'comet-cache').'</option>'."\n";
616
- echo ' </select></p>'."\n";
617
- echo ' <p class="info">'.__('<strong>Note:</strong> Static CDN Filters serve <em>static</em> resources. Static resources, are, simply put, static. Thus, it is not a problem to cache these resources for any visitor (logged-in or not logged-in). To avoid confusion, this defaults to a value of <code>No</code>, and we ask that you set it to <code>Yes</code> on your own so that you\'ll know to expect this behavior; i.e., that static resources will always be served from the CDN (logged-in or not logged-in) even though Logged-In User caching may be disabled above.', 'comet-cache').'</p>'."\n";
618
- echo ' <hr />'."\n";
619
- echo ' <h3>'.__('Disable the Admin Toolbar for Logged-In Users &amp; Comment Authors?', 'comet-cache').'</h3>'."\n";
620
- echo ' <p>'.__('When Logged-In User caching is enabled above, it is recommended that you disable the WordPress Admin Toolbar for logged-in users (on the front-end of the site) because the Toolbar is generally NOT cache-compatible. If you want Comet Cache to automatically disable the Toolbar for logged-in users, you can choose that option below. Or, if you use another plugin to control the Admin Toolbar you can leave this option disabled.', 'comet-cache').'</p>'."\n";
621
- echo ' <p><select name="'.esc_attr(GLOBAL_NS).'[saveOptions][when_logged_in_admin_bar]">'."\n";
622
- echo ' <option value="0"'.selected($this->plugin->options['when_logged_in_admin_bar'], '0', false).'>'.__('Yes, disable the Admin Toolbar for all logged-in users (recommended option).', 'comet-cache').'</option>'."\n";
623
- echo ' <option value="1"'.selected($this->plugin->options['when_logged_in_admin_bar'], '1', false).'>'.__('No, don\'t disable the Admin Toolbar for logged-in users.', 'comet-cache').'</option>'."\n";
624
- echo ' </select></p>'."\n";
625
-
626
- echo ' <p class="info">'.__('<strong>Note:</strong> If you don\'t disable the Admin Toolbar for logged-in users that will cause WordPress Nonce values to appear in the page source; nonce values are generally NOT cache-compatible. Please see <a href="https://cometcache.com/r/kb-article-what-are-wordpress-nonces-and-why-are-they-not-cache-compatible/" target="_blank">this article</a> for details.', 'comet-cache').'</p>'."\n";
 
 
 
 
 
 
 
 
627
  echo ' </div>'."\n";
628
 
629
  echo '</div>'."\n";
@@ -645,7 +666,7 @@ class MenuPageOptions extends MenuPage
645
  echo ' <option value="1"'.selected($this->plugin->options['get_requests'], '1', false).'>'.__('Yes, I would like to cache URLs that contain a query string.', 'comet-cache').'</option>'."\n";
646
  echo ' </select></p>'."\n";
647
  echo ' <p class="info">'.__('<strong>Note:</strong> POST requests (i.e., forms with <code>method=&quot;post&quot;</code>) are always excluded from the cache, which is the way it should be. Any <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html" target="_blank">POST/PUT/DELETE</a> request should NEVER (ever) be cached. CLI (and self-serve) requests are also excluded from the cache (always). A CLI request is one that comes from the command line; commonly used by CRON jobs and other automated routines. A self-serve request is an HTTP connection established from your site -› to your site. For instance, a WP Cron job, or any other HTTP request that is spawned not by a user, but by the server itself.', 'comet-cache').'</p>'."\n";
648
- echo ' <p class="info">'.sprintf(__('<strong>Advanced Tip:</strong> If you are NOT caching GET requests (recommended), but you DO want to allow some special URLs that include query string parameters to be cached; you can add this special parameter to any URL <code>?%2$sAC=1</code>. This tells %1$s that it\'s OK to cache that particular URL, even though it contains query string arguments. If you ARE caching GET requests and you want to force %1$s to NOT cache a specific request, you can add this special parameter to any URL <code>?%2$sAC=0</code>.', 'comet-cache'), esc_html(NAME), esc_html(strtolower(SHORT_NAME))).'</p>'."\n";
649
  echo ' </div>'."\n";
650
 
651
  echo '</div>'."\n";
@@ -695,6 +716,33 @@ class MenuPageOptions extends MenuPage
695
 
696
  /* ----------------------------------------------------------------------------------------- */
697
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
698
  echo '<div class="plugin-menu-page-panel">'."\n";
699
 
700
  echo ' <a href="#" class="plugin-menu-page-panel-heading">'."\n";
@@ -708,6 +756,9 @@ class MenuPageOptions extends MenuPage
708
 
709
  echo ' <p class="info">'.__('<strong>Tip:</strong> let\'s use this example URL: <code>http://www.example.com/post/example-post-123</code>. To exclude this URL, you would put this line into the field above: <code>/post/example-post-123</code>. Or, you could also just put in a small fragment, like: <code>example</code> or <code>example-*-123</code> and that would exclude any URI containing that word fragment.', 'comet-cache').'</p>'."\n";
710
  echo ' <p class="info">'.__('<strong>Note:</strong> please remember that your entries here should be formatted as a line-delimited list; e.g., one exclusion pattern per line.', 'comet-cache').'</p>'."\n";
 
 
 
711
  echo ' </div>'."\n";
712
 
713
  echo '</div>'."\n";
@@ -874,13 +925,6 @@ class MenuPageOptions extends MenuPage
874
  echo ' <p><input type="text" name="'.esc_attr(GLOBAL_NS).'[saveOptions][htmlc_cache_expiration_time]" value="'.esc_attr($this->plugin->options['htmlc_cache_expiration_time']).'" /></p>'."\n";
875
  echo ' <p class="info" style="display:block;">'.__('<strong>Tip:</strong> the value that you specify here MUST be compatible with PHP\'s <a href="http://php.net/manual/en/function.strtotime.php" target="_blank" style="text-decoration:none;"><code>strtotime()</code></a> function. Examples: <code>2 hours</code>, <code>7 days</code>, <code>6 months</code>, <code>1 year</code>.', 'comet-cache').'</p>'."\n";
876
  echo ' <p>'.sprintf(__('<strong>Note:</strong> This does NOT impact the overall cache expiration time that you configure with %1$s. It only impacts the sub-routines provided by the HTML Compressor. In fact, this expiration time is mostly irrelevant. The HTML Compressor uses an internal checksum, and it also checks <code>filemtime()</code> before using an existing cache file. The HTML Compressor class also handles the automatic cleanup of your cache directories to keep it from growing too large over time. Therefore, unless you have VERY little disk space there is no reason to set this to a lower value (even if your site changes dynamically quite often). If anything, you might like to increase this value which could help to further reduce server load. You can <a href="https://github.com/websharks/HTML-Compressor" target="_blank">learn more here</a>. We recommend setting this value to at least double that of your overall %1$s expiration time.', 'comet-cache'), esc_html(NAME)).'</p>'."\n";
877
- echo ' <hr />'."\n";
878
- echo ' <h3>'.__('Enable HTML Compression for Logged-In Users?', 'comet-cache').'</h3>'."\n";
879
- echo ' <p>'.__('Disabled by default. This setting is only applicable when caching for Logged-In Users is enabled. This should remain disabled for logged-in users because the user-specific cache has a much shorter Time To Live (TTL) which means their cache is likely to expire more quickly than a normal visitor. Rebuilding the HTML Compressor cache is time-consuming and doing it too frequently will actually slow things down for them. For example, if you\'re logged into the site as a user and you submit a form, that triggers a clearing of the cache for that user, including the HTML Compressor cache (when Logged-In User caching is enabled). Lots of little actions you take can result in a clearing of the cache. This shorter TTL is not ideal when running the HTML Compressor because it does a deep analysis of the page content and the associated resources in order to intelligently compress things. For logged-in users, it is better to skip that extra work and just cache the HTML source as-is, avoiding that extra overhead. In short, do NOT turn this on unless you know what you\'re doing.', 'comet-cache').'</p>'."\n";
880
- echo ' <p><select name="'.esc_attr(GLOBAL_NS).'[saveOptions][htmlc_when_logged_in]">'."\n";
881
- echo ' <option value="0"'.selected($this->plugin->options['htmlc_when_logged_in'], '0', false).'>'.__('No, disable HTML Compression for logged-in users (recommended).', 'comet-cache').'</option>'."\n";
882
- echo ' <option value="postload"'.selected($this->plugin->options['htmlc_when_logged_in'], 'postload', false).'>'.__('Yes, enable HTML Compression for logged-in users.', 'comet-cache').'</option>'."\n";
883
- echo ' </select></p>'."\n";
884
  echo ' </div>'."\n";
885
  echo ' </div>'."\n";
886
 
@@ -888,27 +932,6 @@ class MenuPageOptions extends MenuPage
888
  }
889
  /* ----------------------------------------------------------------------------------------- */
890
 
891
- echo '<div class="plugin-menu-page-panel">'."\n";
892
-
893
- echo ' <a href="#" class="plugin-menu-page-panel-heading">'."\n";
894
- echo ' <i class="si si-file-archive-o"></i> '.__('GZIP Compression', 'comet-cache')."\n";
895
- echo ' </a>'."\n";
896
-
897
- echo ' <div class="plugin-menu-page-panel-body clearfix">'."\n";
898
- echo ' <img src="'.esc_attr($this->plugin->url('/src/client-s/images/gzip.png')).'" class="screenshot" />'."\n";
899
- echo ' <h3>'.__('<a href="https://developers.google.com/speed/articles/gzip" target="_blank">GZIP Compression</a> (Optional; Highly Recommended)', 'comet-cache').'</h3>'."\n";
900
- echo ' <p>'.__('You don\'t have to use an <code>.htaccess</code> file to enjoy the performance enhancements provided by this plugin; caching is handled automatically by WordPress/PHP alone. That being said, if you want to take advantage of the additional speed enhancements associated w/ GZIP compression (and we do recommend this), then you WILL need an <code>.htaccess</code> file to accomplish that part.', 'comet-cache').'</p>'."\n";
901
- echo ' <p>'.sprintf(__('%1$s fully supports GZIP compression on its output. However, it does not handle GZIP compression directly. We purposely left GZIP compression out of this plugin, because GZIP compression is something that should really be enabled at the Apache level or inside your <code>php.ini</code> file. GZIP compression can be used for things like JavaScript and CSS files as well, so why bother turning it on for only WordPress-generated pages when you can enable GZIP at the server level and cover all the bases!', 'comet-cache'), esc_html(NAME)).'</p>'."\n";
902
- echo ' <p>'.__('If you want to enable GZIP, create an <code>.htaccess</code> file in your WordPress® installation directory, and put the following few lines in it. Alternatively, if you already have an <code>.htaccess</code> file, just add these lines to it, and that is all there is to it. GZIP is now enabled in the recommended way! See also: <a href="https://developers.google.com/speed/articles/gzip" target="_blank"><i class="si si-youtube-play"></i> video about GZIP Compression</a>.', 'comet-cache').'</p>'."\n";
903
- echo ' <pre class="code"><code>'.esc_html(file_get_contents(dirname(__DIR__).'/templates/gzip-htaccess.txt')).'</code></pre>'."\n";
904
- echo ' <hr />'."\n";
905
- echo ' <p class="info" style="display:block;"><strong>Or</strong>, if your server is missing <code>mod_deflate</code>/<code>mod_filter</code>; open your <strong>php.ini</strong> file and add this line: <a href="http://php.net/manual/en/zlib.configuration.php" target="_blank" style="text-decoration:none;"><code>zlib.output_compression = on</code></a></p>'."\n";
906
- echo ' </div>'."\n";
907
-
908
- echo '</div>'."\n";
909
-
910
- /* ----------------------------------------------------------------------------------------- */
911
-
912
  if (IS_PRO || $this->plugin->isProPreview()) {
913
  echo '<div class="plugin-menu-page-panel'.(!IS_PRO ? ' pro-preview' : '').'">'."\n";
914
 
@@ -930,7 +953,9 @@ class MenuPageOptions extends MenuPage
930
  echo ' <option value="0"'.(!IS_PRO ? '' : selected($this->plugin->options['cdn_enable'], '0', false)).'>'.__('No, I do NOT want CDN filters applied at runtime.', 'comet-cache').'</option>'."\n";
931
  echo ' <option value="1"'.(!IS_PRO ? ' selected' : selected($this->plugin->options['cdn_enable'], '1', false)).'>'.__('Yes, I want CDN filters applied w/ my configuration below.', 'comet-cache').'</option>'."\n";
932
  echo ' </select></p>'."\n";
933
-
 
 
934
  echo ' <hr />'."\n";
935
 
936
  echo ' <div class="plugin-menu-page-panel-if-enabled -static-cdn-filter-options">'."\n";
@@ -1009,6 +1034,100 @@ class MenuPageOptions extends MenuPage
1009
  }
1010
  /* ----------------------------------------------------------------------------------------- */
1011
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1012
  if (IS_PRO || $this->plugin->isProPreview()) {
1013
  echo '<div class="plugin-menu-page-panel'.(!IS_PRO ? ' pro-preview' : '').'">'."\n";
1014
 
18
  parent::__construct(); // Parent constructor.
19
 
20
  global $is_nginx; // WP global for web server checks below.
21
+ global $is_apache; // WP global for web server checks below.
22
 
23
  echo '<form id="plugin-menu-page" class="plugin-menu-page" method="post" enctype="multipart/form-data"'.
24
  ' action="'.esc_attr(add_query_arg(urlencode_deep(['page' => GLOBAL_NS, '_wpnonce' => wp_create_nonce()]), self_admin_url('/admin.php'))).'">'."\n";
69
  echo ' <a href="'.esc_attr('http://cometcache.com/blog/').'" target="_blank"><i class="si si-rss-square"></i> '.__('Blog', 'comet-cache').'</a>'."\n";
70
  echo ' </div>'."\n";
71
 
72
+
73
+ echo ' <div class="plugin-menu-page-mailing-list-links">'."\n";
74
  if (!IS_PRO) { // We show these above in the Pro version
 
75
  echo ' <a href="'.esc_attr('http://cometcache.com/r/comet-cache-subscribe/').'" target="_blank"><i class="si si-envelope"></i> '.__('Newsletter', 'comet-cache').'</a>'."\n";
76
  echo ' <a href="'.esc_attr('http://cometcache.com/r/comet-cache-beta-testers-list/').'" target="_blank"><i class="si si-envelope"></i> '.__('Beta Testers', 'comet-cache').'</a>'."\n";
 
77
  }
78
+ echo ' <a href="'.esc_attr('https://twitter.com/cometcache/').'" target="_blank"><i class="si si-twitter"></i> '.__('Twitter', 'comet-cache').'</a>'."\n";
79
+ echo ' <a href="'.esc_attr('https://www.facebook.com/cometcache/').'" target="_blank"><i class="si si-facebook"></i> '.__('Facebook', 'comet-cache').'</a>'."\n";
80
+ echo ' </div>'."\n";
81
+
82
 
83
  if (IS_PRO) {
84
  echo '<div class="plugin-menu-page-version">'."\n";
154
  }
155
  if (!empty($_REQUEST[GLOBAL_NS.'_wp_config_wp_cache_add_failure'])) {
156
  echo '<div class="plugin-menu-page-notice error">'."\n";
157
+ echo ' <i class="si si-thumbs-down"></i> '.__('Failed to update your <code>/wp-config.php</code> file automatically. Please add the following line to your <code>/wp-config.php</code> file (right after the opening <code>&lt;?php</code> tag; on it\'s own line). <pre class="code"><code>define(\'WP_CACHE\', TRUE);</code></pre>', 'comet-cache')."\n";
158
  echo '</div>'."\n";
159
  }
160
  if (!empty($_REQUEST[GLOBAL_NS.'_wp_config_wp_cache_remove_failure'])) {
165
  if (!empty($_REQUEST[GLOBAL_NS.'_advanced_cache_add_failure'])) {
166
  echo '<div class="plugin-menu-page-notice error">'."\n";
167
  if ($_REQUEST[GLOBAL_NS.'_advanced_cache_add_failure'] === 'advanced-cache') {
168
+ echo '<i class="si si-thumbs-down"></i> '.sprintf(__('Failed to update your <code>/wp-content/advanced-cache.php</code> file. Cannot write file: <code>%1$s/%2$s-advanced-cache</code>. Please be sure this directory exists (and that it\'s writable): <code>%1$s</code>. Please use directory permissions <code>755</code> or higher (perhaps <code>777</code>). Once you\'ve done this, please try again.', 'comet-cache'), esc_html($this->plugin->cacheDir()), esc_html(mb_strtolower(SHORT_NAME)))."\n";
169
  } else {
170
  echo '<i class="si si-thumbs-down"></i> '.__('Failed to update your <code>/wp-content/advanced-cache.php</code> file. Most likely a permissions error. Please create an empty file here: <code>/wp-content/advanced-cache.php</code> (just an empty PHP file, with nothing in it); give it permissions <code>644</code> or higher (perhaps <code>666</code>). Once you\'ve done this, please try again.', 'comet-cache')."\n";
171
  }
434
  if (IS_PRO || $this->plugin->isProPreview()) {
435
  echo ' <hr />'."\n";
436
  echo ' <h3 class="'.(!IS_PRO ? 'pro-preview-feature' : '').'">'.__('Misc. Auto-Clear Options', 'comet-cache').'</h3>'."\n";
437
+ echo ' <h4 style="margin-bottom:0;">'.__('Auto-Clear a List of Custom URLs Too?', 'comet-cache').'</h4>'."\n";
438
+ echo ' <p style="margin-top:2px;">'.sprintf(__('When you update a Post/Page, approve a Comment, or make other changes where %1$s can detect that a Post/Page cache should be cleared to keep your site up-to-date; then %1$s will also clear a list of custom URLs that you list here. <strong>Please list one URL per line.</strong> A wildcard <code>*</code> character can also be used when necessary; e.g., <code>https://example.com/category/abc-followed-by-*</code>, (where <code>*</code> = 0 or more characters that are NOT a slash <code>/</code>). Other special characters include: <code>**</code> = 0 or more characters of any kind, including <code>/</code> slashes; <code>^</code> = beginning of the string; <code>$</code> = end of the string. To learn more about this syntax, please see <a href ="http://cometcache.com/r/watered-down-regex-syntax/" target="_blank">this KB article</a>.', 'comet-cache'), esc_html(NAME)).'</p>'."\n";
439
+ echo ' <p><textarea name="'.esc_attr(GLOBAL_NS).'[saveOptions][cache_clear_urls]" spellcheck="false" wrap="off" rows="5">'.format_to_edit($this->plugin->options['cache_clear_urls']).'</textarea></p>'."\n";
440
+ echo ' <p class="info" style="display:block;">'.__('<strong>Note:</strong> Relative URLs (e.g., <code>/name-of-post</code>) should NOT be used. Each entry above should start with <code>http://</code> or <code>https://</code> and include a fully qualified domain name.', 'comet-cache').'</p>'."\n";
441
  }
442
  echo ' </div>'."\n";
443
 
453
  echo ' </a>'."\n";
454
 
455
  echo ' <div class="plugin-menu-page-panel-body clearfix">'."\n";
456
+ if ($this->plugin->isProPreview()) {
457
+ echo ' <img src="'.esc_attr($this->plugin->url('/src/client-s/images/stats-preview.png')).'" style="width:100%;border: 1px dashed #cac9c9;margin-bottom: 20px;">';
458
+ }
459
  echo ' <i class="si si-pie-chart si-4x" style="float:right; margin: 0 0 0 25px;"></i>'."\n";
460
  echo ' <h3>'.__('Enable Cache-Related Stats &amp; Charts?', 'comet-cache').'</h3>'."\n";
461
  echo ' <p>'.sprintf(__('%1$s can collect and display cache-related statistics (including charts). Stats are displayed in the WordPress Admin Bar, and also in your Dashboard under: <strong>%1$s → Stats/Charts</strong>. Cache-related stats provide you with a quick look at what\'s happening behind-the-scenes. Your site grows faster and faster as the cache grows larger in size.', 'comet-cache'), esc_html(NAME)).'</p>'."\n";
547
  echo ' <p style="'.($_sys_getloadavg_unavailable ? 'opacity: 0.5;' : '').'">'.sprintf(__('If you have high traffic at certain times of the day, %1$s can be told to check the current load average via <a href="http://cometcache.com/r/system-load-average-via-php/" target="_blank"><code>sys_getloadavg()</code></a>. If your server\'s load average has been high in the last 15 minutes or so, cache expiration is disabled automatically to help reduce stress on the server; i.e., to avoid generating a new version of the cache while the server is very busy.', 'comet-cache'), esc_html(NAME)).'</p>'."\n";
548
  echo ' <p style="'.($_sys_getloadavg_unavailable ? 'opacity: 0.5;' : '').'">'.sprintf(__('To enable this functionality you should first determine what a high load average is for your server. If you log into your machine via SSH you can run the <code>top</code> command to get a feel for what a high load average looks like. Once you know the number, you can enter it in the field below; e.g., <code>1.05</code> might be a high load average for a server with one CPU. See also: <a href="http://cometcache.com/r/understanding-load-average/" target="_blank">Understanding Load Average</a>', 'comet-cache'), esc_html(NAME)).'</p>'."\n";
549
  echo ' <p><input '.($_sys_getloadavg_unavailable ? 'disabled' : '').' type="text" name="'.esc_attr(GLOBAL_NS).'[saveOptions][cache_max_age_disable_if_load_average_is_gte]" value="'.esc_attr($this->plugin->options['cache_max_age_disable_if_load_average_is_gte']).'" /></p>'."\n";
550
+ if ($_sys_getloadavg_unavailable && mb_stripos(PHP_OS, 'win') === 0) { // See: <http://jas.xyz/1HZsZ9v>
551
  echo ' <p class="warning">'.__('<strong>Note:</strong> It appears that your server is running Windows. The <code>sys_getloadavg()</code> function has not been implemented in PHP for Windows servers yet.', 'comet-cache').'</p>'."\n";
552
+ } elseif ($_sys_getloadavg_unavailable && mb_stripos(PHP_OS, 'win') !== 0) {
553
  echo ' <p class="warning">'.__('<strong>Note:</strong> <code>sys_getloadavg()</code> has been disabled by your web hosting company or is not available on your server.', 'comet-cache').'</p>'."\n";
554
  }
555
  echo ' </div>'."\n";
570
  echo ' <i class="si si-desktop si-4x" style="float:right; margin: 0 0 0 25px;"></i>'."\n";
571
  echo ' <h3>'.__('Allow Double-Caching In The Client-Side Browser?', 'comet-cache').'</h3>'."\n";
572
  echo ' <p>'.__('Recommended setting: <code>No</code> (for membership sites, very important). Otherwise, <code>Yes</code> would be better (if users do NOT log in/out of your site).', 'comet-cache').'</p>'."\n";
573
+ echo ' <p>'.__('<strong>This option is NOT the same as "Leverage Browser Caching"</strong>, which refers to the caching of static resources in the browser (e.g., images, CSS, JS). This Client-Side Cache option is different in that it controls the caching of <em>page content</em> in the browser, i.e., the caching of HTML content generated by PHP itself, which is generally NOT static. If you\'re looking to Leverage Browser Caching for static resources (highly recommended), see the <strong>Apache Optimizations</strong> panel below.', 'comet-cache').'</p>'."\n";
574
  echo ' <p>'.sprintf(__('%1$s handles content delivery through its ability to communicate with a browser using PHP. If you allow a browser to (cache) the caching system itself, you are momentarily losing some control; and this can have a negative impact on users that see more than one version of your site; e.g., one version while logged-in, and another while NOT logged-in. For instance, a user may log out of your site, but upon logging out they report seeing pages on the site which indicate they are STILL logged in (even though they\'re not — that\'s bad). This can happen if you allow a client-side cache, because their browser may cache web pages they visited while logged into your site which persist even after logging out. Sending no-cache headers will work to prevent this issue.', 'comet-cache'), esc_html(NAME)).'</p>'."\n";
575
  echo ' <p>'.__('All of that being said, if all you care about is blazing fast speed and users don\'t log in/out of your site (only you do); you can safely set this to <code>Yes</code> (recommended in this case). Allowing a client-side browser cache will improve speed and reduce outgoing bandwidth when this option is feasible.', 'comet-cache').'</p>'."\n";
576
+ echo ' <p><select name="'.esc_attr(GLOBAL_NS).'[saveOptions][allow_client_side_cache]" data-toggle="enable-disable" data-target=".-client-side-cache-options">'."\n";
577
+ echo ' <option value="0"'.selected($this->plugin->options['allow_client_side_cache'], '0', false).'>'.__('No, prevent a client-side browser cache of dynamic page content (safest option).', 'comet-cache').'</option>'."\n";
578
+ echo ' <option value="1"'.selected($this->plugin->options['allow_client_side_cache'], '1', false).'>'.__('Yes, I will allow a client-side browser cache of pages on the site.', 'comet-cache').'</option>'."\n";
579
  echo ' </select></p>'."\n";
580
  echo ' <p class="info">'.__('<strong>Tip:</strong> Setting this to <code>No</code> is highly recommended when running a membership plugin like <a href="http://wordpress.org/plugins/s2member/" target="_blank">s2Member</a> (as one example). In fact, many plugins like s2Member will send <a href="http://codex.wordpress.org/Function_Reference/nocache_headers" target="_blank">nocache_headers()</a> on their own, so your configuration here will likely be overwritten when you run such plugins (which is better anyway). In short, if you run a membership plugin, you should NOT allow a client-side browser cache.', 'comet-cache').'</p>'."\n";
581
  echo ' <p class="info">'.__('<strong>Tip:</strong> Setting this to <code>No</code> will NOT impact static content; e.g., CSS, JS, images, or other media. This setting pertains only to dynamic PHP scripts which produce content generated by WordPress.', 'comet-cache').'</p>'."\n";
582
+ echo ' <p class="info">'.sprintf(__('<strong>Advanced Tip:</strong> if you have this set to <code>No</code>, but you DO want to allow a few special URLs to be cached by the browser; you can add this parameter to your URL <code>?%2$sABC=1</code>. This tells %1$s that it\'s OK for the browser to cache that particular URL. In other words, the <code>%2$sABC=1</code> parameter tells %1$s NOT to send no-cache headers to the browser.', 'comet-cache'), esc_html(NAME), esc_html(mb_strtolower(SHORT_NAME))).'</p>'."\n";
583
+ echo ' <hr />'."\n";
584
+ echo ' <div class="plugin-menu-page-panel-if-enabled -client-side-cache-options">'."\n";
585
+ echo ' <h3>'.__('Exclusion Patterns for Client-Side Caching', 'comet-cache').'</h3>'."\n";
586
+ echo ' <p>'.__('When you enable Client-Side Caching above, you may want to prevent certain pages on your site from being cached by a client-side browser. This is where you will enter those if you need to (one per line). Searches are performed against the <a href="https://gist.github.com/jaswsinc/338b6eb03a36c048c26f" target="_blank" style="text-decoration:none;"><code>REQUEST_URI</code></a>; i.e., <code>/path/?query</code> (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 <code>*</code> character can also be used when necessary; e.g., <code>/category/abc-followed-by-*</code> (where <code>*</code> = 0 or more characters that are NOT a slash <code>/</code>). Other special characters include: <code>**</code> = 0 or more characters of any kind, including <code>/</code> slashes; <code>^</code> = beginning of the string; <code>$</code> = end of the string. To learn more about this syntax, please see <a href ="http://cometcache.com/r/watered-down-regex-syntax/" target="_blank">this KB article</a>.', 'comet-cache').'</p>'."\n";
587
+ echo ' <p><textarea name="'.esc_attr(GLOBAL_NS).'[saveOptions][exclude_client_side_uris]" rows="5" spellcheck="false" class="monospace">'.format_to_edit($this->plugin->options['exclude_client_side_uris']).'</textarea></p>'."\n";
588
+ echo ' <p class="info">'.__('<strong>Tip:</strong> let\'s use this example URL: <code>http://www.example.com/post/example-post-123</code>. To exclude this URL, you would put this line into the field above: <code>/post/example-post-123</code>. Or, you could also just put in a small fragment, like: <code>example</code> or <code>example-*-123</code> and that would exclude any URI containing that word fragment.', 'comet-cache').'</p>'."\n";
589
+ echo ' <p class="info">'.__('<strong>Note:</strong> please remember that your entries here should be formatted as a line-delimited list; e.g., one exclusion pattern per line.', 'comet-cache').'</p>'."\n";
590
+ echo ' </div>'."\n";
591
  echo ' </div>'."\n";
592
 
593
  echo '</div>'."\n";
607
  echo ' <p>'.__('This should almost ALWAYS be set to <code>No</code>. Most sites will NOT want to cache content generated while a user is logged-in. Doing so could result in a cache of dynamic content generated specifically for a particular user, where the content being cached may contain details that pertain only to the user that was logged-in when the cache was generated. Imagine visiting a website that says you\'re logged-in as Billy Bob (but you\'re not Billy Bob; NOT good). In short, do NOT turn this on unless you know what you\'re doing.', 'comet-cache').'</p>'."\n";
608
  echo ' <i class="si si-sitemap si-4x" style="float:right; margin: 0 0 0 25px;"></i>'."\n";
609
  echo ' <p>'.sprintf(__('<strong>Exception (Membership Sites):</strong> If you run a site with many users and the majority of your traffic comes from users who ARE logged-in, please choose: <code>Yes (maintain separate cache)</code>. %1$s will operate normally; but when a user is logged-in, the cache is user-specific. %1$s will intelligently refresh the cache when/if a user submits a form on your site with the GET or POST method. Or, if you make changes to their account (or another plugin makes changes to their account); including user <a href="http://codex.wordpress.org/Function_Reference/update_user_option" target="_blank">option</a>|<a href="http://codex.wordpress.org/Function_Reference/update_user_meta" target="_blank">meta</a> additions, updates &amp; deletions too. However, please note that enabling this feature (e.g., user-specific cache entries); will eat up MUCH more disk space. That being said, the benefits of this feature for most sites will outweigh the disk overhead (e.g., it\'s NOT an issue in most cases). Unless you are short on disk space (or you have MANY thousands of users), the disk overhead is neglible.', 'comet-cache'), esc_html(NAME)).'</p>'."\n";
610
+ echo ' <p><select name="'.esc_attr(GLOBAL_NS).'[saveOptions][when_logged_in]" data-toggle="enable-disable" data-enabled-strings="1,postload" data-target=".-logged-in-users-options">'."\n";
611
+ echo ' <option value="0"'.(!IS_PRO ? '' : selected($this->plugin->options['when_logged_in'], '0', false)).'>'.__('No, do NOT cache; or serve a cache file when a user is logged-in (safest option).', 'comet-cache').'</option>'."\n";
612
+ echo ' <option value="postload"'.(!IS_PRO ? ' selected' : selected($this->plugin->options['when_logged_in'], 'postload', false)).'>'.__('Yes, and maintain a separate cache for each user (recommended for membership sites).', 'comet-cache').'</option>'."\n";
613
  if ($this->plugin->options['when_logged_in'] === '1' || get_site_option(GLOBAL_NS.'_when_logged_in_was_1')) {
614
  update_site_option(GLOBAL_NS.'_when_logged_in_was_1', '1');
615
  echo ' <option value="1"'.selected($this->plugin->options['when_logged_in'], '1', false).'>'.__('Yes, but DON\'T maintain a separate cache for each user (I know what I\'m doing).', 'comet-cache').'</option>'."\n";
621
  echo ' <p class="info">'.__('<strong>Note:</strong> For most sites, the majority of their traffic (if not all of their traffic) comes from visitors who are not logged in, so disabling the cache for logged-in users is NOT ordinarily a performance issue. When a user IS logged-in, disabling the cache is considered ideal, because a logged-in user has a session open with your site; and the content they view should remain very dynamic in this scenario.', 'comet-cache').'</p>'."\n";
622
  echo ' <p class="info">'.sprintf(__('<strong>Note:</strong> This setting includes some users who AREN\'T actually logged into the system, but who HAVE authored comments recently. %1$s includes comment authors as part of it\'s logged-in user check. This way comment authors will be able to see updates to the comment thread immediately; and, so that any dynamically-generated messages displayed by your theme will work as intended. In short, %1$s thinks of a comment author as a logged-in user, even though technically they are not. ~ Users who gain access to password-protected Posts/Pages are also included.', 'comet-cache'), esc_html(NAME)).'</p>'."\n";
623
  echo ' <hr />'."\n";
624
+ echo ' <div class="plugin-menu-page-panel-if-enabled -logged-in-users-options">'."\n";
625
+ echo ' <h3>'.__('Static CDN Filters Enabled for Logged-In Users &amp; Comment Authors?', 'comet-cache').'</h3>'."\n";
626
+ echo ' <p>'.__('While this defaults to a value of <code>No</code>, it should almost always be set to <code>Yes</code>. This value defaults to <code>No</code> only because Logged-In User caching (see above) defaults to <code>No</code> and setting this value to <code>Yes</code> by default can cause confusion for some users. Once you understand that Static CDN Filters can be applied safely for all visitors (logged-in or not logged-in), please choose <code>Yes</code> in the dropdown below. If you are not using Static CDN Filters, the value below is ignored.', 'comet-cache').'</p>'."\n";
627
+ echo ' <p><select name="'.esc_attr(GLOBAL_NS).'[saveOptions][cdn_when_logged_in]">'."\n";
628
+ echo ' <option value="0"'.selected($this->plugin->options['cdn_when_logged_in'], '0', false).'>'.__('No, disable Static CDN Filters when a user is logged-in.', 'comet-cache').'</option>'."\n";
629
+ echo ' <option value="postload"'.selected($this->plugin->options['cdn_when_logged_in'], 'postload', false).'>'.__('Yes, enable Static CDN Filters for logged-in users (recommended) .', 'comet-cache').'</option>'."\n";
630
+ echo ' </select></p>'."\n";
631
+ echo ' <p class="info">'.__('<strong>Note:</strong> Static CDN Filters serve <em>static</em> resources. Static resources, are, simply put, static. Thus, it is not a problem to cache these resources for any visitor (logged-in or not logged-in). To avoid confusion, this defaults to a value of <code>No</code>, and we ask that you set it to <code>Yes</code> on your own so that you\'ll know to expect this behavior; i.e., that static resources will always be served from the CDN (logged-in or not logged-in) even though Logged-In User caching may be disabled above.', 'comet-cache').'</p>'."\n";
632
+ echo ' <hr />'."\n";
633
+ echo ' <h3>'.__('Disable the Admin Toolbar for Logged-In Users &amp; Comment Authors?', 'comet-cache').'</h3>'."\n";
634
+ echo ' <p>'.__('When Logged-In User caching is enabled above, it is recommended that you disable the WordPress Admin Toolbar for logged-in users (on the front-end of the site) because the Toolbar is generally NOT cache-compatible. If you want Comet Cache to automatically disable the Toolbar for logged-in users, you can choose that option below. Or, if you use another plugin to control the Admin Toolbar you can leave this option disabled.', 'comet-cache').'</p>'."\n";
635
+ echo ' <p><select name="'.esc_attr(GLOBAL_NS).'[saveOptions][when_logged_in_admin_bar]">'."\n";
636
+ echo ' <option value="0"'.selected($this->plugin->options['when_logged_in_admin_bar'], '0', false).'>'.__('Yes, disable the Admin Toolbar for all logged-in users (recommended option).', 'comet-cache').'</option>'."\n";
637
+ echo ' <option value="1"'.selected($this->plugin->options['when_logged_in_admin_bar'], '1', false).'>'.__('No, don\'t disable the Admin Toolbar for logged-in users.', 'comet-cache').'</option>'."\n";
638
+ echo ' </select></p>'."\n";
639
+ echo ' <p class="info">'.__('<strong>Note:</strong> If you don\'t disable the Admin Toolbar for logged-in users that will cause WordPress Nonce values to appear in the page source; nonce values are generally NOT cache-compatible. Please see <a href="https://cometcache.com/r/kb-article-what-are-wordpress-nonces-and-why-are-they-not-cache-compatible/" target="_blank">this article</a> for details.', 'comet-cache').'</p>'."\n";
640
+ echo ' <hr />'."\n";
641
+ echo ' <h3>'.__('Enable HTML Compression for Logged-In Users?', 'comet-cache').'</h3>'."\n";
642
+ echo ' <p>'.__('Disabled by default. This setting is only applicable when HTML Compression is enabled. HTML Compression should remain disabled for logged-in users because the user-specific cache has a much shorter Time To Live (TTL) which means their cache is likely to expire more quickly than a normal visitor. Rebuilding the HTML Compressor cache is time-consuming and doing it too frequently will actually slow things down for them. For example, if you\'re logged into the site as a user and you submit a form, that triggers a clearing of the cache for that user, including the HTML Compressor cache. Lots of little actions you take can result in a clearing of the cache. This shorter TTL is not ideal when running the HTML Compressor because it does a deep analysis of the page content and the associated resources in order to intelligently compress things. For logged-in users, it is better to skip that extra work and just cache the HTML source as-is, avoiding that extra overhead. In short, do NOT turn this on unless you know what you\'re doing.', 'comet-cache').'</p>'."\n";
643
+ echo ' <p><select name="'.esc_attr(GLOBAL_NS).'[saveOptions][htmlc_when_logged_in]">'."\n";
644
+ echo ' <option value="0"'.selected($this->plugin->options['htmlc_when_logged_in'], '0', false).'>'.__('No, disable HTML Compression for logged-in users (recommended).', 'comet-cache').'</option>'."\n";
645
+ echo ' <option value="postload"'.selected($this->plugin->options['htmlc_when_logged_in'], 'postload', false).'>'.__('Yes, enable HTML Compression for logged-in users.', 'comet-cache').'</option>'."\n";
646
+ echo ' </select></p>'."\n";
647
+ echo ' </div>'."\n";
648
  echo ' </div>'."\n";
649
 
650
  echo '</div>'."\n";
666
  echo ' <option value="1"'.selected($this->plugin->options['get_requests'], '1', false).'>'.__('Yes, I would like to cache URLs that contain a query string.', 'comet-cache').'</option>'."\n";
667
  echo ' </select></p>'."\n";
668
  echo ' <p class="info">'.__('<strong>Note:</strong> POST requests (i.e., forms with <code>method=&quot;post&quot;</code>) are always excluded from the cache, which is the way it should be. Any <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html" target="_blank">POST/PUT/DELETE</a> request should NEVER (ever) be cached. CLI (and self-serve) requests are also excluded from the cache (always). A CLI request is one that comes from the command line; commonly used by CRON jobs and other automated routines. A self-serve request is an HTTP connection established from your site -› to your site. For instance, a WP Cron job, or any other HTTP request that is spawned not by a user, but by the server itself.', 'comet-cache').'</p>'."\n";
669
+ echo ' <p class="info">'.sprintf(__('<strong>Advanced Tip:</strong> If you are NOT caching GET requests (recommended), but you DO want to allow some special URLs that include query string parameters to be cached; you can add this special parameter to any URL <code>?%2$sAC=1</code>. This tells %1$s that it\'s OK to cache that particular URL, even though it contains query string arguments. If you ARE caching GET requests and you want to force %1$s to NOT cache a specific request, you can add this special parameter to any URL <code>?%2$sAC=0</code>.', 'comet-cache'), esc_html(NAME), esc_html(mb_strtolower(SHORT_NAME))).'</p>'."\n";
670
  echo ' </div>'."\n";
671
 
672
  echo '</div>'."\n";
716
 
717
  /* ----------------------------------------------------------------------------------------- */
718
 
719
+ $exclude_hosts_option_enable = is_multisite() &&
720
+ ((defined('SUBDOMAIN_INSTALL') && SUBDOMAIN_INSTALL) || $this->plugin->canConsiderDomainMapping());
721
+
722
+ if ($this->plugin->applyWpFilters(GLOBAL_NS.'_exclude_hosts_option_enable', $exclude_hosts_option_enable)) {
723
+ // Display option panel for Host Exclusion Patterns.
724
+
725
+ echo '<div class="plugin-menu-page-panel">'."\n";
726
+
727
+ echo ' <a href="#" class="plugin-menu-page-panel-heading">'."\n";
728
+ echo ' <i class="si si-ban"></i> '.__('Host Exclusion Patterns', 'comet-cache')."\n";
729
+ echo ' </a>'."\n";
730
+
731
+ echo ' <div class="plugin-menu-page-panel-body clearfix">'."\n";
732
+ echo ' <h3>'.__('Don\'t Cache These Special Host Exclusion Patterns?', 'comet-cache').'</h3>'."\n";
733
+ echo ' <p>'.__('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., <code>site1.example.com</code>.', 'comet-cache').'</p>'."\n";
734
+ echo ' <p>'.__('This field also supports <a href ="http://cometcache.com/r/watered-down-regex-syntax/" target="_blank" style="text-decoration:none;">Watered-Down Regex</a> syntax, which means that you can also exclude a pattern like: <code>*.example.com</code> or <code>*.example.*</code>. 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: <code>*.mynetwork.com</code>. That excludes all sub-domains, but not <code>mynetwork.com</code> by itself.', 'comet-cache').'</p>'."\n";
735
+
736
+ echo ' <p><textarea name="'.esc_attr(GLOBAL_NS).'[saveOptions][exclude_hosts]" rows="5" spellcheck="false" class="monospace">'.format_to_edit($this->plugin->options['exclude_hosts']).'</textarea></p>'."\n";
737
+
738
+ echo ' <p class="info">'.__('<strong>Note:</strong> please remember that your entries here should be formatted as a line-delimited list; e.g., one exclusion pattern per line.', 'comet-cache').'</p>'."\n";
739
+
740
+ echo ' </div>'."\n";
741
+ echo '</div>'."\n";
742
+ }
743
+
744
+ /* ----------------------------------------------------------------------------------------- */
745
+
746
  echo '<div class="plugin-menu-page-panel">'."\n";
747
 
748
  echo ' <a href="#" class="plugin-menu-page-panel-heading">'."\n";
756
 
757
  echo ' <p class="info">'.__('<strong>Tip:</strong> let\'s use this example URL: <code>http://www.example.com/post/example-post-123</code>. To exclude this URL, you would put this line into the field above: <code>/post/example-post-123</code>. Or, you could also just put in a small fragment, like: <code>example</code> or <code>example-*-123</code> and that would exclude any URI containing that word fragment.', 'comet-cache').'</p>'."\n";
758
  echo ' <p class="info">'.__('<strong>Note:</strong> please remember that your entries here should be formatted as a line-delimited list; e.g., one exclusion pattern per line.', 'comet-cache').'</p>'."\n";
759
+ if (is_multisite() && defined('SUBDOMAIN_INSTALL') && !SUBDOMAIN_INSTALL) {
760
+ echo ' <p class="info">'.__('<strong>Multisite Network w/ Sub-Directories:</strong> You can also use URI Exclusion Patterns to exclude specific sites from being cached, e.g., <code>/site1/*</code>.', 'comet-cache').'</p>'."\n";
761
+ }
762
  echo ' </div>'."\n";
763
 
764
  echo '</div>'."\n";
925
  echo ' <p><input type="text" name="'.esc_attr(GLOBAL_NS).'[saveOptions][htmlc_cache_expiration_time]" value="'.esc_attr($this->plugin->options['htmlc_cache_expiration_time']).'" /></p>'."\n";
926
  echo ' <p class="info" style="display:block;">'.__('<strong>Tip:</strong> the value that you specify here MUST be compatible with PHP\'s <a href="http://php.net/manual/en/function.strtotime.php" target="_blank" style="text-decoration:none;"><code>strtotime()</code></a> function. Examples: <code>2 hours</code>, <code>7 days</code>, <code>6 months</code>, <code>1 year</code>.', 'comet-cache').'</p>'."\n";
927
  echo ' <p>'.sprintf(__('<strong>Note:</strong> This does NOT impact the overall cache expiration time that you configure with %1$s. It only impacts the sub-routines provided by the HTML Compressor. In fact, this expiration time is mostly irrelevant. The HTML Compressor uses an internal checksum, and it also checks <code>filemtime()</code> before using an existing cache file. The HTML Compressor class also handles the automatic cleanup of your cache directories to keep it from growing too large over time. Therefore, unless you have VERY little disk space there is no reason to set this to a lower value (even if your site changes dynamically quite often). If anything, you might like to increase this value which could help to further reduce server load. You can <a href="https://github.com/websharks/HTML-Compressor" target="_blank">learn more here</a>. We recommend setting this value to at least double that of your overall %1$s expiration time.', 'comet-cache'), esc_html(NAME)).'</p>'."\n";
 
 
 
 
 
 
 
928
  echo ' </div>'."\n";
929
  echo ' </div>'."\n";
930
 
932
  }
933
  /* ----------------------------------------------------------------------------------------- */
934
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
935
  if (IS_PRO || $this->plugin->isProPreview()) {
936
  echo '<div class="plugin-menu-page-panel'.(!IS_PRO ? ' pro-preview' : '').'">'."\n";
937
 
953
  echo ' <option value="0"'.(!IS_PRO ? '' : selected($this->plugin->options['cdn_enable'], '0', false)).'>'.__('No, I do NOT want CDN filters applied at runtime.', 'comet-cache').'</option>'."\n";
954
  echo ' <option value="1"'.(!IS_PRO ? ' selected' : selected($this->plugin->options['cdn_enable'], '1', false)).'>'.__('Yes, I want CDN filters applied w/ my configuration below.', 'comet-cache').'</option>'."\n";
955
  echo ' </select></p>'."\n";
956
+ if ($is_apache && $this->plugin->options['cdn_enable'] && !$this->plugin->options['htaccess_access_control_allow_origin']) {
957
+ echo ' <p class="warning" style="display:block;">'.__('<strong>Warning:</strong> Static CDN Filters are enabled above but the <strong>Comet Cache → Plugin Options → Apache Optimizations → Send Access-Control-Allow-Origin Header</strong> option has been disabled. We recommend sending the <code>Access-Control-Allow-Origin</code> header to avoid <a href="https://cometcache.com/r/kb-article-what-are-cross-origin-request-blocked-cors-errors/" target="_blank">CORS errors</a> when a CDN is configured.', 'comet-cache').'</p>'."\n";
958
+ }
959
  echo ' <hr />'."\n";
960
 
961
  echo ' <div class="plugin-menu-page-panel-if-enabled -static-cdn-filter-options">'."\n";
1034
  }
1035
  /* ----------------------------------------------------------------------------------------- */
1036
 
1037
+ if ($is_apache || $this->plugin->isProPreview()) {
1038
+
1039
+ echo '<div class="plugin-menu-page-panel'.(!IS_PRO && $this->plugin->isProPreview() ? ' pro-preview' : '').'">'."\n";
1040
+
1041
+ echo ' <a href="#" class="plugin-menu-page-panel-heading'.((!IS_PRO && $this->plugin->isProPreview()) ? ' pro-preview-additional-features' : '').'">'."\n";
1042
+ echo ' <i class="si si-server"></i> '.__('Apache Optimizations', 'comet-cache')."\n";
1043
+ echo ' </a>'."\n";
1044
+
1045
+ echo ' <div class="plugin-menu-page-panel-body clearfix">'."\n";
1046
+ echo ' <img src="'.esc_attr($this->plugin->url('/src/client-s/images/apache.png')).'" class="screenshot" />'."\n";
1047
+ echo ' <h3>'.__('Apache Performance Tuning (Optional; Highly Recommended)', 'comet-cache').'</h3>'."\n";
1048
+ echo ' <p>'.__('You don\'t need to use an <code>.htaccess</code> file to enjoy the performance enhancements provided by this plugin; caching is handled automatically by WordPress/PHP alone. That being said, if you want to take advantage of additional speed enhancements by optimizing the Apache web server to achieve maximize performance (and we do recommend this), then you WILL need an <code>.htaccess</code> file to accomplish that part.', 'comet-cache').'</p>'."\n";
1049
+ echo ' <p>'.__('WordPress itself uses the <code>.htaccess</code> file to create Apache rewrite rules when you enable fancy Permalinks, so there\'s a good chance you already have an <code>.htaccess</code> file. The options below allow for additional performance tuning using recommendations provided by Comet Cache.', 'comet-cache').'</p>'."\n";
1050
+ echo ' <p>'.__('When you enable one of the options below, Comet Cache will attempt to automatically insert the appropriate configuration into your <code>.htaccess</code> file (or remove it automatically if you are disabling an option). If Comet Cache is unable to update the file, or if you would prefer to add the configuration yourself, the recommended configuration to add to the file can be viewed at the bottom of each option.', 'comet-cache').'</p>'."\n";
1051
+ echo ' <p class="info" style="display:block;">'.__('<strong>Note:</strong> The <code>.htaccess</code> file is parsed by the web server directly, before WordPress is even loaded. For that reason, if something goes wrong in the file you can end up with a broken site. We recommend creating a backup of your current <code>.htaccess</code> file before making any modifications.', 'comet-cache').'</p>'."\n";
1052
+ echo ' <hr />'."\n";
1053
+ echo ' <h3>'.__('Enable GZIP Compression?', 'comet-cache').'</h3>'."\n";
1054
+ echo ' <p>'.__('<a href="https://cometcache.com/r/google-developers-gzip-compression/" target="_blank">GZIP compression</a> is highly recommended. It\'s not uncommon to achieve compression rates as high as 70-90%, which is a huge savings in the amount of data that needs to be transferred with each visit to your site.', 'comet-cache').'</p>'."\n";
1055
+ echo ' <p>'.sprintf(__('%1$s fully supports GZIP compression on its output. However, it does not handle GZIP compression directly like some caching plugins. We purposely left GZIP compression out of this plugin because GZIP compression is something that should really be enabled at the Apache level or inside your <code>php.ini</code> file. GZIP compression can be used for things like JavaScript and CSS files as well, so why bother turning it on for only WordPress-generated pages when you can enable GZIP at the server level and cover all the bases!', 'comet-cache'), esc_html(NAME)).'</p>'."\n";
1056
+ echo ' <p><select name="'.esc_attr(GLOBAL_NS).'[saveOptions][htaccess_gzip_enable]" data-target=".-htaccess-gzip-enable-options">'."\n";
1057
+ echo ' <option value="0"'.selected($this->plugin->options['htaccess_gzip_enable'], '0', false).'>'.__('No, do NOT enable GZIP Compression (or I\'ll update my configuration manually; see below)', 'comet-cache').'</option>'."\n";
1058
+ echo ' <option value="1"'.selected($this->plugin->options['htaccess_gzip_enable'], '1', false).'>'.__('Yes, enable GZIP Compression (recommended)', 'comet-cache').'</option>'."\n";
1059
+ echo ' </select></p>'."\n";
1060
+ echo ' <p>'.__('Or, you can update your configuration manually: [<a href="#" data-toggle-target=".'.esc_attr(GLOBAL_NS.'-apache-optimizations--gzip-configuration').'"><i class="si si-eye"></i> .htaccess configuration <i class="si si-eye"></i></a>]', 'comet-cache').'</p>'."\n";
1061
+ echo ' <div class="'.esc_attr(GLOBAL_NS.'-apache-optimizations--gzip-configuration').'" style="display:none; margin-top:1em;">'."\n";
1062
+ echo ' <p>'.__('<strong>To enable GZIP compression:</strong> Create or edit the <code>.htaccess</code> file in your WordPress installation directory and add the following lines to the top:', 'comet-cache').'</p>'."\n";
1063
+ echo ' <pre class="code"><code>'.esc_html($this->plugin->fillReplacementCodes(file_get_contents(dirname(__DIR__).'/templates/htaccess/gzip-enable.txt'))).'</code></pre>'."\n";
1064
+ echo ' <p class="info" style="display:block;">'.__('<strong>Or</strong>, if your server is missing <code>mod_deflate</code>/<code>mod_filter</code>; open your <code>php.ini</code> file and add this line: <a href="http://php.net/manual/en/zlib.configuration.php" target="_blank" style="text-decoration:none;"><code>zlib.output_compression = on</code></a>', 'comet-cache').'</p>'."\n";
1065
+ echo ' </div>'."\n";
1066
+
1067
+ if ((!IS_PRO && $is_apache) && !$this->plugin->isProPreview()) {
1068
+ echo ' <hr />'."\n";
1069
+ echo ' <p class="warning" style="display:block;">'.__('<a href="'.esc_attr(add_query_arg(urlencode_deep(['page' => GLOBAL_NS, GLOBAL_NS.'_pro_preview' => '1']), self_admin_url('/admin.php'))).'">Enable the Pro Preview</a> to see <strong>Leverage Browser Caching</strong>, <strong>Enforce Canonical URLs</strong>, and more!', 'comet-cache').'</p>'."\n";
1070
+ }
1071
+
1072
+ if (IS_PRO || $this->plugin->isProPreview()) {
1073
+ echo ' <hr />'."\n";
1074
+ echo ' <h3 class="'.(!IS_PRO ? 'pro-preview-feature' : '').'">'.__('Leverage Browser Caching?', 'comet-cache').'</h3>'."\n";
1075
+ echo ' <p>'.__('<a href="https://cometcache.com/r/google-developers-http-caching/" target="_blank">Browser Caching</a> is highly recommended. When loading a single page, downloading all of the resources for that page may require multiple roundtrips between the browser and server, which delays processing and may block rendering of page content. This also incurs data costs for the visitor. With browser caching, your server tells the visitor\'s browser that it is allowed to cache static resources for a certain amount of time (Google recommends 1 week and that\'s what Comet Cache uses).', 'comet-cache').'</p>'."\n";
1076
+ echo ' <p>'.__('In WordPress, \'Page Caching\' is all about server-side performance (reducing the amount of time it takes the server to generate the page content). With Comet Cache installed, you\'re drastically reducing page generation time. However, you can make a vistior\'s experience ​<em>even faster</em>​ when you leverage browser caching too. When this option is enabled, the visitor\'s browser will cache static resources from each page and reuse those cached resources on subsequent page loads. In this way, future visits to the same page will not require additional connections to your site to download static resources that the visitor\'s browser has already cached.', 'comet-cache').'</p>'."\n";
1077
+ echo ' <p><select name="'.esc_attr(GLOBAL_NS).'[saveOptions][htaccess_browser_caching_enable]" data-target=".-htaccess-browser-caching-enable-options">'."\n";
1078
+ echo ' <option value="0"'.(!IS_PRO ? '' : selected($this->plugin->options['htaccess_browser_caching_enable'], '0', false)).'>'.__('No, do NOT enable Browser Caching (or I\'ll update my configuration manually; see below)', 'comet-cache').'</option>'."\n";
1079
+ echo ' <option value="1"'.(!IS_PRO ? 'selected' : selected($this->plugin->options['htaccess_browser_caching_enable'], '1', false)).'>'.__('Yes, enable Browser Caching for static resources (recommended)', 'comet-cache').'</option>'."\n";
1080
+ echo ' </select></p>'."\n";
1081
+ echo ' <p>'.__('Or, you can update your configuration manually: [<a href="#" data-toggle-target=".'.esc_attr(GLOBAL_NS.'-apache-optimizations--leverage-browser-caching').'"><i class="si si-eye"></i> .htaccess configuration <i class="si si-eye"></i></a>]', 'comet-cache').'</p>'."\n";
1082
+ echo ' <div class="'.esc_attr(GLOBAL_NS.'-apache-optimizations--leverage-browser-caching').'" style="display:none; margin-top:1em;">'."\n";
1083
+ echo ' <p>'.__('<strong>To enable Browser Caching:</strong> Create or edit the <code>.htaccess</code> file in your WordPress installation directory and add the following lines to the top:', 'comet-cache').'</p>'."\n";
1084
+ echo ' <pre class="code"><code>'.esc_html($this->plugin->fillReplacementCodes(file_get_contents(dirname(__DIR__).'/templates/htaccess/browser-caching-enable.txt'))).'</code></pre>'."\n";
1085
+ echo ' </div>'."\n";
1086
+ }
1087
+
1088
+ if ((IS_PRO && !empty($GLOBALS['wp_rewrite']->permalink_structure)) || $this->plugin->isProPreview()) {
1089
+ echo ' <hr />'."\n";
1090
+ echo ' <h3 class="'.(!IS_PRO ? 'pro-preview-feature' : '').'">'.__('Enforce Canonical URLs?', 'comet-cache').'</h3>'."\n";
1091
+ echo ' <p>'.__('Permalinks (URLs) leading to Posts/Pages on your site (based on your WordPress Permalink Settings) '.($GLOBALS['wp_rewrite']->use_trailing_slashes ? 'require a <code>.../trailing-slash/</code>' : 'do not require a <code>.../trailing-slash</code>').'. Ordinarily, WordPress enforces this by redirecting a request for '.($GLOBALS['wp_rewrite']->use_trailing_slashes ? '<code>.../something</code>' : '<code>.../something/</code>').', to '.($GLOBALS['wp_rewrite']->use_trailing_slashes ? '<code>.../something/</code>' : '<code>.../something</code>').', thereby forcing the final location to match your Permalink configuration. However, whenever you install a plugin like Comet Cache, much of WordPress (including this automatic redirection) is out of the picture when the cached copy of a page is being served. So enabling this option will add rules to your <code>.htaccess</code> file that make Apache aware of your WordPess Permalink configuration. Apache can do what WordPress normally would, only much more efficiently.', 'comet-cache').'</p>'."\n";
1092
+ echo ' <p><select name="'.esc_attr(GLOBAL_NS).'[saveOptions][htaccess_enforce_canonical_urls]" data-target=".-htaccess-enforce-canonical-urls-options">'."\n";
1093
+ echo ' <option value="0"'.(!IS_PRO ? '' : selected($this->plugin->options['htaccess_enforce_canonical_urls'], '0', false)).'>'.__('No, do NOT enforce canonical URLs (or I\'ll update my configuration manually; see below)', 'comet-cache').'</option>'."\n";
1094
+ echo ' <option value="1"'.(!IS_PRO ? 'selected' : selected($this->plugin->options['htaccess_enforce_canonical_urls'], '1', false)).'>'.__('Yes, enforce canonical URLs (recommended)', 'comet-cache').'</option>'."\n";
1095
+ echo ' </select></p>'."\n";
1096
+ echo ' <p>'.__('Or, you can update your configuration manually: [<a href="#" data-toggle-target=".'.esc_attr(GLOBAL_NS.'-apache-optimizations--enforce-cononical-urls').'"><i class="si si-eye"></i> .htaccess configuration <i class="si si-eye"></i></a>]', 'comet-cache').'</p>'."\n";
1097
+ echo ' <div class="'.esc_attr(GLOBAL_NS.'-apache-optimizations--enforce-cononical-urls').'" style="display:none; margin-top:1em;">'."\n";
1098
+ echo ' <p>'.__('<strong>To enforce Canonical URLs:</strong> Create or edit the <code>.htaccess</code> file in your WordPress installation directory and add the following lines to the top:', 'comet-cache').'</p>'."\n";
1099
+ if ($GLOBALS['wp_rewrite']->use_trailing_slashes) {
1100
+ echo ' <pre class="code"><code>'.esc_html($this->plugin->fillReplacementCodes(file_get_contents(dirname(__DIR__).'/templates/htaccess/canonical-urls-ts-enable.txt'))).'</code></pre>'."\n";
1101
+ } else {
1102
+ echo ' <pre class="code"><code>'.esc_html($this->plugin->fillReplacementCodes(file_get_contents(dirname(__DIR__).'/templates/htaccess/canonical-urls-no-ts-enable.txt'))).'</code></pre>'."\n";
1103
+ }
1104
+ echo ' </div>'."\n";
1105
+ }
1106
+
1107
+ if ((IS_PRO && $this->plugin->options['cdn_enable']) || $this->plugin->isProPreview()) {
1108
+ echo ' <hr />'."\n";
1109
+ echo ' <h3 class="'.(!IS_PRO ? 'pro-preview-feature' : '').'">'.__('Send Access-Control-Allow-Origin Header?', 'comet-cache').'</h3>'."\n";
1110
+ if ($this->plugin->options['cdn_enable'] && !$this->plugin->options['htaccess_access_control_allow_origin']) {
1111
+ echo ' <p class="warning" style="display:block;">'.__('<strong>Warning:</strong> Send Access-Control-Allow-Origin Header has been disabled below but <strong>Comet Cache → Plugin Options → Static CDN Filters</strong> are enabled. We recommend configuring your server to send the <code>Access-Control-Allow-Origin</code> header to avoid <a href="https://cometcache.com/r/kb-article-what-are-cross-origin-request-blocked-cors-errors/" target="_blank">CORS errors</a> when a CDN is configured.', 'comet-cache').'</p>'."\n";
1112
+ }
1113
+ echo ' <p>'.__('If you are using Static CDN Filters to load resources for your site from another domain, it\'s important that your server sends an <code>Access-Control-Allow-Origin</code> header to prevent Cross Origin Resource Sharing (CORS) errors. This option is enabled automatically when you enable Static CDN Filters. For more information, see <a href="https://cometcache.com/r/kb-article-what-are-cross-origin-request-blocked-cors-errors/" target="_blank">this article</a>.', 'comet-cache').'</p>'."\n";
1114
+ echo ' <p><select name="'.esc_attr(GLOBAL_NS).'[saveOptions][htaccess_access_control_allow_origin]" data-target=".-htaccess-access-control-allow-origin-options">'."\n";
1115
+ echo ' <option value="0"'.(!IS_PRO ? '' : selected($this->plugin->options['htaccess_access_control_allow_origin'], '0', false)).'>'.__('No, do NOT send the Access-Control-Allow-Origin header (or I\'ll update my configuration manually; see below)', 'comet-cache').'</option>'."\n";
1116
+ echo ' <option value="1"'.(!IS_PRO ? 'selected' : selected($this->plugin->options['htaccess_access_control_allow_origin'], '1', false)).'>'.__('Yes, send the Access-Control-Allow-Origin header (recommended for Static CDN Filters)', 'comet-cache').'</option>'."\n";
1117
+ echo ' </select></p>'."\n";
1118
+ echo ' <p>'.__('Or, you can update your configuration manually: [<a href="#" data-toggle-target=".'.esc_attr(GLOBAL_NS.'-apache-optimizations--access-control-allow-origin').'"><i class="si si-eye"></i> .htaccess configuration <i class="si si-eye"></i></a>]', 'comet-cache').'</p>'."\n";
1119
+ echo ' <div class="'.esc_attr(GLOBAL_NS.'-apache-optimizations--access-control-allow-origin').'" style="display:none; margin-top:1em;">'."\n";
1120
+ echo ' <p>'.__('<strong>To send the Access-Control-Allow-Origin header:</strong> Create or edit the <code>.htaccess</code> file in your WordPress installation directory and add the following lines to the top:', 'comet-cache').'</p>'."\n";
1121
+ echo ' <pre class="code"><code>'.esc_html($this->plugin->fillReplacementCodes(file_get_contents(dirname(__DIR__).'/templates/htaccess/access-control-allow-origin-enable.txt'))).'</code></pre>'."\n";
1122
+ echo ' </div>'."\n";
1123
+ }
1124
+ echo ' </div>'."\n";
1125
+ echo '</div>'."\n";
1126
+
1127
+ }
1128
+
1129
+ /* ----------------------------------------------------------------------------------------- */
1130
+
1131
  if (IS_PRO || $this->plugin->isProPreview()) {
1132
  echo '<div class="plugin-menu-page-panel'.(!IS_PRO ? ' pro-preview' : '').'">'."\n";
1133
 
src/includes/classes/Plugin.php CHANGED
@@ -218,6 +218,10 @@ class Plugin extends AbsBaseAp
218
  'auto_cache_other_urls',
219
  'auto_cache_user_agent',
220
 
 
 
 
 
221
  'cdn_enable',
222
  'cdn_host',
223
  'cdn_hosts',
@@ -306,7 +310,7 @@ class Plugin extends AbsBaseAp
306
 
307
  /* Misc. cache behaviors. */
308
 
309
- 'allow_browser_cache' => '0', // `0|1`.
310
  'when_logged_in' => '0', // `0|1|postload`.
311
  'get_requests' => '0', // `0|1`.
312
  'feeds_enable' => '0', // `0|1`.
@@ -316,6 +320,7 @@ class Plugin extends AbsBaseAp
316
 
317
  /* Related to exclusions. */
318
 
 
319
  'exclude_uris' => '', // Empty string or line-delimited patterns.
320
  'exclude_client_side_uris' => '', // Line-delimited list of URIs.
321
  'exclude_refs' => '', // Empty string or line-delimited patterns.
@@ -356,6 +361,13 @@ class Plugin extends AbsBaseAp
356
  'auto_cache_other_urls' => '', // A line-delimited list of any other URLs.
357
  'auto_cache_user_agent' => 'WordPress',
358
 
 
 
 
 
 
 
 
359
  /* Related to CDN functionality. */
360
 
361
  'cdn_enable' => '0', // `0|1`; enable CDN filters?
@@ -474,7 +486,9 @@ class Plugin extends AbsBaseAp
474
  add_action('clean_post_cache', [$this, 'autoClearPostCache']);
475
  add_action('post_updated', [$this, 'autoClearAuthorPageCache'], 10, 3);
476
  add_action('pre_post_update', [$this, 'autoClearPostCacheTransition'], 10, 2);
 
477
  add_action('woocommerce_product_set_stock', [$this, 'autoClearPostCacheOnWooCommerceSetStock'], 10, 1);
 
478
 
479
  add_action('added_term_relationship', [$this, 'autoClearPostTermsCache'], 10, 1);
480
  add_action('delete_term_relationships', [$this, 'autoClearPostTermsCache'], 10, 1);
218
  'auto_cache_other_urls',
219
  'auto_cache_user_agent',
220
 
221
+ 'htaccess_browser_caching_enable',
222
+ 'htaccess_enforce_canonical_urls',
223
+ 'htaccess_access_control_allow_origin',
224
+
225
  'cdn_enable',
226
  'cdn_host',
227
  'cdn_hosts',
310
 
311
  /* Misc. cache behaviors. */
312
 
313
+ 'allow_client_side_cache' => '0', // `0|1`.
314
  'when_logged_in' => '0', // `0|1|postload`.
315
  'get_requests' => '0', // `0|1`.
316
  'feeds_enable' => '0', // `0|1`.
320
 
321
  /* Related to exclusions. */
322
 
323
+ 'exclude_hosts' => '', // Empty string or line-delimited patterns.
324
  'exclude_uris' => '', // Empty string or line-delimited patterns.
325
  'exclude_client_side_uris' => '', // Line-delimited list of URIs.
326
  'exclude_refs' => '', // Empty string or line-delimited patterns.
361
  'auto_cache_other_urls' => '', // A line-delimited list of any other URLs.
362
  'auto_cache_user_agent' => 'WordPress',
363
 
364
+ /* Related to .htaccess tweaks. */
365
+
366
+ 'htaccess_browser_caching_enable' => '0', // `0|1`; enable browser caching?
367
+ 'htaccess_gzip_enable' => '0', // `0|1`; enable GZIP compression?
368
+ 'htaccess_enforce_canonical_urls' => '0', // `0|1`; enforce canonical URLs?
369
+ 'htaccess_access_control_allow_origin' => '0', // `0|1`; send Access-Control-Allow-Origin header?
370
+
371
  /* Related to CDN functionality. */
372
 
373
  'cdn_enable' => '0', // `0|1`; enable CDN filters?
486
  add_action('clean_post_cache', [$this, 'autoClearPostCache']);
487
  add_action('post_updated', [$this, 'autoClearAuthorPageCache'], 10, 3);
488
  add_action('pre_post_update', [$this, 'autoClearPostCacheTransition'], 10, 2);
489
+
490
  add_action('woocommerce_product_set_stock', [$this, 'autoClearPostCacheOnWooCommerceSetStock'], 10, 1);
491
+ add_action('update_option_comment_mail_options', [$this, 'autoClearCache']);
492
 
493
  add_action('added_term_relationship', [$this, 'autoClearPostTermsCache'], 10, 1);
494
  add_action('delete_term_relationships', [$this, 'autoClearPostTermsCache'], 10, 1);
src/includes/classes/VsUpgrades.php CHANGED
@@ -42,6 +42,7 @@ class VsUpgrades extends AbsBase
42
  $this->fromLte151114();
43
  $this->fromZenCache();
44
  $this->fromLte160227();
 
45
  }
46
 
47
  /**
@@ -91,22 +92,22 @@ class VsUpgrades extends AbsBase
91
  {
92
  if (version_compare($this->prev_version, '151107', '<=')) {
93
  if (is_array($existing_options = get_site_option(GLOBAL_NS.'_options'))) {
94
- if (!empty($existing_options['cache_clear_xml_sitemap_patterns']) && strpos($existing_options['cache_clear_xml_sitemap_patterns'], '**') === false) {
95
  $this->plugin->options['cache_clear_xml_sitemap_patterns'] = str_replace('*', '**', $existing_options['cache_clear_xml_sitemap_patterns']);
96
  }
97
- if (!empty($existing_options['exclude_uris']) && strpos($existing_options['exclude_uris'], '**') === false) {
98
  $this->plugin->options['exclude_uris'] = str_replace('*', '**', $existing_options['exclude_uris']);
99
  }
100
- if (!empty($existing_options['exclude_refs']) && strpos($existing_options['exclude_refs'], '**') === false) {
101
  $this->plugin->options['exclude_refs'] = str_replace('*', '**', $existing_options['exclude_refs']);
102
  }
103
- if (!empty($existing_options['exclude_agents']) && strpos($existing_options['exclude_agents'], '**') === false) {
104
  $this->plugin->options['exclude_agents'] = str_replace('*', '**', $existing_options['exclude_agents']);
105
  }
106
- if (!empty($existing_options['htmlc_css_exclusions']) && strpos($existing_options['htmlc_css_exclusions'], '**') === false) {
107
  $this->plugin->options['htmlc_css_exclusions'] = str_replace('*', '**', $existing_options['htmlc_css_exclusions']);
108
  }
109
- if (!empty($existing_options['htmlc_js_exclusions']) && strpos($existing_options['htmlc_js_exclusions'], '**') === false) {
110
  $this->plugin->options['htmlc_js_exclusions'] = str_replace('*', '**', $existing_options['htmlc_js_exclusions']);
111
  }
112
  if ($existing_options['cdn_blacklisted_extensions'] === 'eot,ttf,otf,woff') {
@@ -186,7 +187,7 @@ class VsUpgrades extends AbsBase
186
 
187
  global $is_apache; // Remove htaccess rules added by ZenCache so that they can be re-added by Comet Cache
188
  if ($is_apache && $this->plugin->findHtaccessMarker('WmVuQ2FjaGU') && ($htaccess = $this->plugin->readHtaccessFile())) {
189
- $regex = '/#\s*BEGIN\s+ZenCache\s+WmVuQ2FjaGU.*?#\s*END\s+ZenCache\s+WmVuQ2FjaGU\s*/is';
190
  $htaccess['file_contents'] = preg_replace($regex, '', $htaccess['file_contents']);
191
 
192
  $this->plugin->writeHtaccessFile($htaccess, false);
@@ -223,4 +224,39 @@ class VsUpgrades extends AbsBase
223
  }
224
  }
225
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
226
  }
42
  $this->fromLte151114();
43
  $this->fromZenCache();
44
  $this->fromLte160227();
45
+ $this->fromLte160521();
46
  }
47
 
48
  /**
92
  {
93
  if (version_compare($this->prev_version, '151107', '<=')) {
94
  if (is_array($existing_options = get_site_option(GLOBAL_NS.'_options'))) {
95
+ if (!empty($existing_options['cache_clear_xml_sitemap_patterns']) && mb_strpos($existing_options['cache_clear_xml_sitemap_patterns'], '**') === false) {
96
  $this->plugin->options['cache_clear_xml_sitemap_patterns'] = str_replace('*', '**', $existing_options['cache_clear_xml_sitemap_patterns']);
97
  }
98
+ if (!empty($existing_options['exclude_uris']) && mb_strpos($existing_options['exclude_uris'], '**') === false) {
99
  $this->plugin->options['exclude_uris'] = str_replace('*', '**', $existing_options['exclude_uris']);
100
  }
101
+ if (!empty($existing_options['exclude_refs']) && mb_strpos($existing_options['exclude_refs'], '**') === false) {
102
  $this->plugin->options['exclude_refs'] = str_replace('*', '**', $existing_options['exclude_refs']);
103
  }
104
+ if (!empty($existing_options['exclude_agents']) && mb_strpos($existing_options['exclude_agents'], '**') === false) {
105
  $this->plugin->options['exclude_agents'] = str_replace('*', '**', $existing_options['exclude_agents']);
106
  }
107
+ if (!empty($existing_options['htmlc_css_exclusions']) && mb_strpos($existing_options['htmlc_css_exclusions'], '**') === false) {
108
  $this->plugin->options['htmlc_css_exclusions'] = str_replace('*', '**', $existing_options['htmlc_css_exclusions']);
109
  }
110
+ if (!empty($existing_options['htmlc_js_exclusions']) && mb_strpos($existing_options['htmlc_js_exclusions'], '**') === false) {
111
  $this->plugin->options['htmlc_js_exclusions'] = str_replace('*', '**', $existing_options['htmlc_js_exclusions']);
112
  }
113
  if ($existing_options['cdn_blacklisted_extensions'] === 'eot,ttf,otf,woff') {
187
 
188
  global $is_apache; // Remove htaccess rules added by ZenCache so that they can be re-added by Comet Cache
189
  if ($is_apache && $this->plugin->findHtaccessMarker('WmVuQ2FjaGU') && ($htaccess = $this->plugin->readHtaccessFile())) {
190
+ $regex = '/#\s*BEGIN\s+ZenCache\s+WmVuQ2FjaGU.*?#\s*END\s+ZenCache\s+WmVuQ2FjaGU\s*/uis';
191
  $htaccess['file_contents'] = preg_replace($regex, '', $htaccess['file_contents']);
192
 
193
  $this->plugin->writeHtaccessFile($htaccess, false);
224
  }
225
  }
226
  }
227
+
228
+ /**
229
+ * Before we renamed the Auto-Cache Engine requirements check notice to `auto_cache_engine_minimum_requirements`,
230
+ * and before we renamed the `allow_browser_cache` option to `allow_client_side_cache`,
231
+ * and before we added the `htaccess_access_control_allow_origin` option,
232
+ * and before we renamed COMET_CACHE_ALLOW_BROWSER_CACHE to COMET_CACHE_ALLOW_CLIENT_SIDE_CACHE.
233
+ *
234
+ * @since 160706
235
+ */
236
+ protected function fromLte160521()
237
+ {
238
+ if (version_compare($this->prev_version, '160521', '<=')) {
239
+ global $is_apache; // WP global for web server checks below.
240
+
241
+ $this->plugin->dismissMainNotice('allow_url_fopen_disabled');
242
+ $this->plugin->removeAdvancedCache();
243
+
244
+ if (is_array($existing_options = get_site_option(GLOBAL_NS.'_options'))) {
245
+ if (isset($existing_options['allow_browser_cache'])) {
246
+ $this->plugin->options['allow_client_side_cache'] = $existing_options['allow_browser_cache'];
247
+ }
248
+ if (isset($existing_options['cdn_enable'])) {
249
+ $this->plugin->options['htaccess_access_control_allow_origin'] = $existing_options['cdn_enable'];
250
+ }
251
+ if ($this->plugin->options !== $existing_options) {
252
+ $this->plugin->updateOptions($this->plugin->options); // Save/update options.
253
+ $this->plugin->activate(); // Reactivate plugin w/ new options.
254
+ }
255
+ }
256
+
257
+ if ($is_apache) {
258
+ $this->plugin->enqueueMainNotice(sprintf(__('<strong>New %1$s Feature!</strong> This release of %1$s includes a whole new panel for Apache Performance Tuning. Visit the <a href="%2$s">settings</a> and see the new options in <strong>Comet Cache → Plugin Options → Apache Optimizations</strong>.', 'comet-cache'), esc_html(NAME), esc_attr(add_query_arg(urlencode_deep(['page' => GLOBAL_NS]), self_admin_url('/admin.php')))));
259
+ }
260
+ }
261
+ }
262
  }
src/includes/interfaces/Shared/NcDebugConsts.php CHANGED
@@ -192,6 +192,15 @@ interface NcDebugConsts
192
  */
193
  const NC_DEBUG_PREVIEW = 'nc_debug_preview';
194
 
 
 
 
 
 
 
 
 
 
195
  /**
196
  * No-cache because the current request excluded by its URI.
197
  *
192
  */
193
  const NC_DEBUG_PREVIEW = 'nc_debug_preview';
194
 
195
+ /**
196
+ * No-cache because the current request is excluded by its host name.
197
+ *
198
+ * @since 160706 Host exclusions.
199
+ *
200
+ * @type string A unique string identifier in the set of `NC_DEBUG_` constants.
201
+ */
202
+ const NC_DEBUG_EXCLUDED_HOSTS = 'nc_debug_excluded_hosts';
203
+
204
  /**
205
  * No-cache because the current request excluded by its URI.
206
  *
src/includes/stub.php CHANGED
@@ -13,11 +13,11 @@ if (!defined('WPINC')) {
13
  require_once dirname(__DIR__).'/vendor/autoload.php';
14
  require_once __DIR__.'/functions/i18n-utils.php';
15
 
16
- ${__FILE__}['version'] = '160521'; //version//
17
  ${__FILE__}['plugin'] = dirname(dirname(__DIR__));
18
  ${__FILE__}['plugin'] .= '/'.basename(${__FILE__}['plugin']).'.php';
19
  ${__FILE__}['ns_path'] = str_replace('\\', '/', __NAMESPACE__); // To dir/path.
20
- ${__FILE__}['is_pro'] = strtolower(basename(${__FILE__}['ns_path'])) === 'pro';
21
 
22
  define(__NAMESPACE__.'\\SHORT_NAME', 'CC');
23
  define(__NAMESPACE__.'\\NAME', 'Comet Cache');
13
  require_once dirname(__DIR__).'/vendor/autoload.php';
14
  require_once __DIR__.'/functions/i18n-utils.php';
15
 
16
+ ${__FILE__}['version'] = '160706'; //version//
17
  ${__FILE__}['plugin'] = dirname(dirname(__DIR__));
18
  ${__FILE__}['plugin'] .= '/'.basename(${__FILE__}['plugin']).'.php';
19
  ${__FILE__}['ns_path'] = str_replace('\\', '/', __NAMESPACE__); // To dir/path.
20
+ ${__FILE__}['is_pro'] = mb_strtolower(basename(${__FILE__}['ns_path'])) === 'pro';
21
 
22
  define(__NAMESPACE__.'\\SHORT_NAME', 'CC');
23
  define(__NAMESPACE__.'\\NAME', 'Comet Cache');
src/includes/templates/ac-plugin.txt CHANGED
@@ -15,9 +15,9 @@ function my_ac_plugin() // Example plugin.
15
  }
16
  function my_ac_version_salt_shaker($version_salt)
17
  {
18
- if (stripos($_SERVER['HTTP_USER_AGENT'], 'iphone') !== false) {
19
  $version_salt .= 'iphones'; // Give iPhones their own variation of the cache.
20
- } elseif (stripos($_SERVER['HTTP_USER_AGENT'], 'android') !== false) {
21
  $version_salt .= 'androids'; // Androic variation.
22
  } else {
23
  $version_salt .= 'other'; // A default group.
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.
src/includes/templates/advanced-cache.txt CHANGED
@@ -37,6 +37,7 @@ if (defined('WP_DEBUG') && WP_DEBUG) {
37
  }
38
  Classes\AdvCacheBackCompat::zenCacheConstants();
39
  Classes\AdvCacheBackCompat::zcRequestVars();
 
40
 
41
  if (!defined('COMET_CACHE_PRO')) {
42
  /**
@@ -68,7 +69,7 @@ if (!defined('COMET_CACHE_DEBUGGING_ENABLE')) {
68
  */
69
  define('COMET_CACHE_DEBUGGING_ENABLE', '%%COMET_CACHE_DEBUGGING_ENABLE%%');
70
  }
71
- if (!defined('COMET_CACHE_ALLOW_BROWSER_CACHE')) {
72
  /**
73
  * Allow browsers to cache each document?
74
  *
@@ -79,7 +80,7 @@ if (!defined('COMET_CACHE_ALLOW_BROWSER_CACHE')) {
79
  * @note If this is a `FALSE` (or an empty) value; Comet Cache will send no-cache headers.
80
  * If `TRUE`, Comet Cache will NOT send no-cache headers.
81
  */
82
- define('COMET_CACHE_ALLOW_BROWSER_CACHE', '%%COMET_CACHE_ALLOW_BROWSER_CACHE%%');
83
  }
84
  if (!defined('COMET_CACHE_GET_REQUESTS')) {
85
  /**
@@ -153,6 +154,16 @@ if (!defined('COMET_CACHE_MAX_AGE')) {
153
  define('COMET_CACHE_MAX_AGE', '%%COMET_CACHE_MAX_AGE%%');
154
  }
155
 
 
 
 
 
 
 
 
 
 
 
156
  if (!defined('COMET_CACHE_EXCLUDE_URIS')) {
157
  /**
158
  * URI exclusions.
37
  }
38
  Classes\AdvCacheBackCompat::zenCacheConstants();
39
  Classes\AdvCacheBackCompat::zcRequestVars();
40
+ Classes\AdvCacheBackCompat::browserCacheConstant();
41
 
42
  if (!defined('COMET_CACHE_PRO')) {
43
  /**
69
  */
70
  define('COMET_CACHE_DEBUGGING_ENABLE', '%%COMET_CACHE_DEBUGGING_ENABLE%%');
71
  }
72
+ if (!defined('COMET_CACHE_ALLOW_CLIENT_SIDE_CACHE')) {
73
  /**
74
  * Allow browsers to cache each document?
75
  *
80
  * @note If this is a `FALSE` (or an empty) value; Comet Cache will send no-cache headers.
81
  * If `TRUE`, Comet Cache will NOT send no-cache headers.
82
  */
83
+ define('COMET_CACHE_ALLOW_CLIENT_SIDE_CACHE', '%%COMET_CACHE_ALLOW_CLIENT_SIDE_CACHE%%');
84
  }
85
  if (!defined('COMET_CACHE_GET_REQUESTS')) {
86
  /**
154
  define('COMET_CACHE_MAX_AGE', '%%COMET_CACHE_MAX_AGE%%');
155
  }
156
 
157
+ if (!defined('COMET_CACHE_EXCLUDE_HOSTS')) {
158
+ /**
159
+ * Host exclusions.
160
+ *
161
+ * @since 160706 Adding host exclusions.
162
+ *
163
+ * @var string A regular expression; else an empty string.
164
+ */
165
+ define('COMET_CACHE_EXCLUDE_HOSTS', '%%COMET_CACHE_EXCLUDE_HOSTS%%');
166
+ }
167
  if (!defined('COMET_CACHE_EXCLUDE_URIS')) {
168
  /**
169
  * URI exclusions.
src/includes/templates/gzip-htaccess.txt DELETED
@@ -1,10 +0,0 @@
1
- <IfModule deflate_module>
2
- <IfModule filter_module>
3
- AddOutputFilterByType DEFLATE text/plain text/html
4
- AddOutputFilterByType DEFLATE text/xml application/xml application/xhtml+xml application/xml-dtd
5
- AddOutputFilterByType DEFLATE application/rdf+xml application/rss+xml application/atom+xml image/svg+xml
6
- AddOutputFilterByType DEFLATE text/css text/javascript application/javascript application/x-javascript
7
- AddOutputFilterByType DEFLATE font/otf font/opentype application/font-otf application/x-font-otf
8
- AddOutputFilterByType DEFLATE font/ttf font/truetype application/font-ttf application/x-font-ttf
9
- </IfModule>
10
- </IfModule>
 
 
 
 
 
 
 
 
 
 
src/includes/templates/htaccess/access-control-allow-origin-enable.txt ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
1
+ # Send Access-Control-Allow-Origin header for Static CDN Filters.
2
+ <IfModule headers_module>
3
+ <FilesMatch "\.(ttf|ttc|otf|eot|woff|woff2|font.css|css|js)$">
4
+ Header set Access-Control-Allow-Origin "*"
5
+ </FilesMatch>
6
+ </IfModule>
src/includes/templates/htaccess/browser-caching-enable.txt ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
1
+ # Enable browser caching.
2
+ FileETag mtime size
3
+
4
+ <IfModule expires_module>
5
+ ExpiresActive on
6
+ ExpiresDefault "access plus 1 week"
7
+ </IfModule>
src/includes/templates/htaccess/canonical-urls-no-ts-enable.txt ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Force NO trailing slash on all virtual requests (except WP admin area).
2
+ <IfModule rewrite_module>
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
+ # If there is a trailing slash.
14
+ RewriteCond %{REQUEST_URI} /$
15
+
16
+ # Force NO trailing slash on all virtual requests.
17
+ RewriteRule ^(.*)/$ /$1 [QSA,L,R=301]
18
+ </IfModule>
src/includes/templates/htaccess/canonical-urls-ts-enable.txt ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Force a trailing slash on all virtual requests (except WP admin area).
2
+ <IfModule rewrite_module>
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
+ # If there is no trailing slash.
14
+ RewriteCond %{REQUEST_URI} !/$
15
+
16
+ # Force a trailing slash on all virtual requests.
17
+ RewriteRule ^(.*)$ /$1/ [QSA,L,R=301]
18
+ </IfModule>
src/includes/templates/htaccess/gzip-enable.txt ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ # Enable GZIP compression.
2
+ <IfModule deflate_module>
3
+ <IfModule filter_module>
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
+ </IfModule>
11
+ </IfModule>
src/includes/traits/Ac/{BrowserUtils.php → ClientSideUtils.php} RENAMED
@@ -3,7 +3,7 @@ namespace WebSharks\CometCache\Traits\Ac;
3
 
4
  use WebSharks\CometCache\Classes;
5
 
6
- trait BrowserUtils
7
  {
8
  /**
9
  * Sends no-cache headers (if applicable).
@@ -12,24 +12,28 @@ trait BrowserUtils
12
  */
13
  public function maybeStopBrowserCaching()
14
  {
15
- switch ((bool) COMET_CACHE_ALLOW_BROWSER_CACHE) {
 
 
 
 
16
 
17
  case true: // If global config allows, check exclusions.
18
 
19
- if (isset($_GET[strtolower(SHORT_NAME).'ABC'])) {
20
- if (!filter_var($_GET[strtolower(SHORT_NAME).'ABC'], FILTER_VALIDATE_BOOLEAN)) {
21
  return $this->sendNoCacheHeaders(); // Disallow.
22
  } // Else, allow client-side caching; because `ABC` is a true-ish value.
23
  // ↑ Note that exclusion patterns are ignored in this case, in favor of `ABC`.
24
- } elseif (COMET_CACHE_EXCLUDE_CLIENT_SIDE_URIS && preg_match(COMET_CACHE_EXCLUDE_CLIENT_SIDE_URIS, $_SERVER['REQUEST_URI'])) {
25
  return $this->sendNoCacheHeaders(); // Disallow.
26
  }
27
- return; // Allow browser caching; default behavior in this mode.
28
 
29
  case false: // Global config disallows; check inclusions.
30
 
31
- if (isset($_GET[strtolower(SHORT_NAME).'ABC'])) {
32
- if (filter_var($_GET[strtolower(SHORT_NAME).'ABC'], FILTER_VALIDATE_BOOLEAN)) {
33
  return; // Allow, because `ABC` is a false-ish value.
34
  } // Else, disallow client-side caching; because `ABC` is a true-ish value.
35
  // ↑ Note that inclusion patterns are ignored in this case, in favor of `ABC`.
3
 
4
  use WebSharks\CometCache\Classes;
5
 
6
+ trait ClientSideUtils
7
  {
8
  /**
9
  * Sends no-cache headers (if applicable).
12
  */
13
  public function maybeStopBrowserCaching()
14
  {
15
+ if (!defined('COMET_CACHE_ALLOW_CLIENT_SIDE_CACHE')) {
16
+ return $this->sendNoCacheHeaders(); // Upgrading from <= v160521, before we renamed this constant. Return default.
17
+ }
18
+
19
+ switch ((bool) COMET_CACHE_ALLOW_CLIENT_SIDE_CACHE) {
20
 
21
  case true: // If global config allows, check exclusions.
22
 
23
+ if (isset($_GET[mb_strtolower(SHORT_NAME).'ABC'])) {
24
+ if (!filter_var($_GET[mb_strtolower(SHORT_NAME).'ABC'], FILTER_VALIDATE_BOOLEAN)) {
25
  return $this->sendNoCacheHeaders(); // Disallow.
26
  } // Else, allow client-side caching; because `ABC` is a true-ish value.
27
  // ↑ Note that exclusion patterns are ignored in this case, in favor of `ABC`.
28
+ } elseif (COMET_CACHE_EXCLUDE_CLIENT_SIDE_URIS && (empty($_SERVER['REQUEST_URI']) || preg_match(COMET_CACHE_EXCLUDE_CLIENT_SIDE_URIS, $_SERVER['REQUEST_URI']))) {
29
  return $this->sendNoCacheHeaders(); // Disallow.
30
  }
31
+ return; // Allow client-side caching; default behavior in this mode.
32
 
33
  case false: // Global config disallows; check inclusions.
34
 
35
+ if (isset($_GET[mb_strtolower(SHORT_NAME).'ABC'])) {
36
+ if (filter_var($_GET[mb_strtolower(SHORT_NAME).'ABC'], FILTER_VALIDATE_BOOLEAN)) {
37
  return; // Allow, because `ABC` is a false-ish value.
38
  } // Else, disallow client-side caching; because `ABC` is a true-ish value.
39
  // ↑ Note that inclusion patterns are ignored in this case, in favor of `ABC`.
src/includes/traits/Ac/NcDebugUtils.php CHANGED
@@ -111,7 +111,7 @@ trait NcDebugUtils
111
  break; // Break switch handler.
112
 
113
  case $this::NC_DEBUG_AC_GET_VAR:
114
- $reason = sprintf(__('because `$_GET[\'%1$sAC\']` is set to a boolean-ish FALSE value.', 'comet-cache'), strtolower(SHORT_NAME));
115
  break; // Break switch handler.
116
 
117
  case $this::NC_DEBUG_UNCACHEABLE_REQUEST:
@@ -163,6 +163,10 @@ trait NcDebugUtils
163
  $reason = __('because `$_REQUEST` indicates this is simply a preview of something to come.', 'comet-cache');
164
  break; // Break switch handler.
165
 
 
 
 
 
166
  case $this::NC_DEBUG_EXCLUDED_URIS:
167
  $reason = __('because `$_SERVER[\'REQUEST_URI\']` matches a configured URI Exclusion Pattern on this installation.', 'comet-cache');
168
  break; // Break switch handler.
111
  break; // Break switch handler.
112
 
113
  case $this::NC_DEBUG_AC_GET_VAR:
114
+ $reason = sprintf(__('because `$_GET[\'%1$sAC\']` is set to a boolean-ish FALSE value.', 'comet-cache'), mb_strtolower(SHORT_NAME));
115
  break; // Break switch handler.
116
 
117
  case $this::NC_DEBUG_UNCACHEABLE_REQUEST:
163
  $reason = __('because `$_REQUEST` indicates this is simply a preview of something to come.', 'comet-cache');
164
  break; // Break switch handler.
165
 
166
+ case $this::NC_DEBUG_EXCLUDED_HOSTS:
167
+ $reason = __('because `$_SERVER[\'HTTP_HOST\']` matches a configured Host Exclusion Pattern on this installation.', 'comet-cache');
168
+ break; // Break switch handler.
169
+
170
  case $this::NC_DEBUG_EXCLUDED_URIS:
171
  $reason = __('because `$_SERVER[\'REQUEST_URI\']` matches a configured URI Exclusion Pattern on this installation.', 'comet-cache');
172
  break; // Break switch handler.
src/includes/traits/Ac/ObUtils.php CHANGED
@@ -126,7 +126,7 @@ trait ObUtils
126
  if (isset($_SERVER['DONOTCACHEPAGE'])) {
127
  return $this->maybeSetDebugInfo($this::NC_DEBUG_DONOTCACHEPAGE_SERVER_VAR);
128
  }
129
- if (isset($_GET[strtolower(SHORT_NAME).'AC']) && !filter_var($_GET[strtolower(SHORT_NAME).'AC'], FILTER_VALIDATE_BOOLEAN)) {
130
  return $this->maybeSetDebugInfo($this::NC_DEBUG_AC_GET_VAR);
131
  }
132
  if ($this->isUncacheableRequestMethod()) {
@@ -140,13 +140,13 @@ trait ObUtils
140
  if (!COMET_CACHE_FEEDS_ENABLE && $this->isFeed()) {
141
  return $this->maybeSetDebugInfo($this::NC_DEBUG_FEED_REQUEST);
142
  }
143
- if (preg_match('/\/(?:wp\-[^\/]+|xmlrpc)\.php(?:[?]|$)/i', $_SERVER['REQUEST_URI'])) {
144
  return $this->maybeSetDebugInfo($this::NC_DEBUG_WP_SYSTEMATICS);
145
  }
146
- if (is_admin() || preg_match('/\/wp-admin(?:[\/?]|$)/i', $_SERVER['REQUEST_URI'])) {
147
  return $this->maybeSetDebugInfo($this::NC_DEBUG_WP_ADMIN);
148
  }
149
- if (is_multisite() && preg_match('/\/files(?:[\/?]|$)/i', $_SERVER['REQUEST_URI'])) {
150
  return $this->maybeSetDebugInfo($this::NC_DEBUG_MS_FILES);
151
  }
152
  if ((!IS_PRO || !COMET_CACHE_WHEN_LOGGED_IN) && $this->isLikeUserLoggedIn()) {
@@ -158,6 +158,9 @@ trait ObUtils
158
  if (!empty($_REQUEST['preview'])) {
159
  return $this->maybeSetDebugInfo($this::NC_DEBUG_PREVIEW);
160
  }
 
 
 
161
  if (COMET_CACHE_EXCLUDE_URIS && preg_match(COMET_CACHE_EXCLUDE_URIS, $_SERVER['REQUEST_URI'])) {
162
  return $this->maybeSetDebugInfo($this::NC_DEBUG_EXCLUDED_URIS);
163
  }
@@ -202,7 +205,7 @@ trait ObUtils
202
 
203
  $headers_list = $this->headersList();
204
  foreach (unserialize($headers) as $_header) {
205
- if (!in_array($_header, $headers_list, true) && stripos($_header, 'Last-Modified:') !== 0) {
206
  header($_header); // Only cacheable/safe headers are stored in the cache.
207
  }
208
  }
@@ -271,7 +274,7 @@ trait ObUtils
271
  if ((!IS_PRO || !COMET_CACHE_WHEN_LOGGED_IN) && $this->isLikeUserLoggedIn()) {
272
  return (boolean) $this->maybeSetDebugInfo($this::NC_DEBUG_IS_LIKE_LOGGED_IN_USER);
273
  }
274
- if (!COMET_CACHE_CACHE_NONCE_VALUES && preg_match('/\b(?:_wpnonce|akismet_comment_nonce)\b/', $cache)) {
275
  if (IS_PRO && COMET_CACHE_WHEN_LOGGED_IN && $this->isLikeUserLoggedIn()) {
276
  if (!COMET_CACHE_CACHE_NONCE_VALUES_WHEN_LOGGED_IN) {
277
  return (boolean) $this->maybeSetDebugInfo($this::NC_DEBUG_IS_LOGGED_IN_USER_NONCE);
@@ -283,7 +286,7 @@ trait ObUtils
283
  if ($this->is_404 && !COMET_CACHE_CACHE_404_REQUESTS) {
284
  return (boolean) $this->maybeSetDebugInfo($this::NC_DEBUG_404_REQUEST);
285
  }
286
- if (stripos($cache, '<body id="error-page">') !== false) {
287
  return (boolean) $this->maybeSetDebugInfo($this::NC_DEBUG_WP_ERROR_PAGE);
288
  }
289
  if (!$this->hasACacheableContentType()) {
@@ -334,8 +337,9 @@ trait ObUtils
334
 
335
  if (COMET_CACHE_DEBUGGING_ENABLE && $this->isHtmlXmlDoc($cache)) {
336
  $total_time = number_format(microtime(true) - $this->timer, 5, '.', ''); // Based on the original timer.
 
337
  $cache .= "\n".'<!-- '.htmlspecialchars(sprintf(__('%1$s file path: %2$s', 'comet-cache'), NAME, str_replace(WP_CONTENT_DIR, '', $this->is_404 ? $this->cache_file_404 : $this->cache_file))).' -->';
338
- $cache .= "\n".'<!-- '.htmlspecialchars(sprintf(__('%1$s file built for (%2$s%3$s) in %4$s seconds, on: %5$s.', 'comet-cache'), NAME, $this->is_404 ? '404 [error document]' : $this->salt_location, (IS_PRO && COMET_CACHE_WHEN_LOGGED_IN && $this->user_token ? '; '.sprintf(__('user token: %1$s', 'comet-cache'), $this->user_token) : ''), $total_time, date('M jS, Y @ g:i a T'))).' -->';
339
  $cache .= "\n".'<!-- '.htmlspecialchars(sprintf(__('This %1$s file will auto-expire (and be rebuilt) on: %2$s (based on your configured expiration time).', 'comet-cache'), NAME, date('M jS, Y @ g:i a T', strtotime('+'.COMET_CACHE_MAX_AGE)))).' -->';
340
  }
341
  if ($this->is_404) {
126
  if (isset($_SERVER['DONOTCACHEPAGE'])) {
127
  return $this->maybeSetDebugInfo($this::NC_DEBUG_DONOTCACHEPAGE_SERVER_VAR);
128
  }
129
+ if (isset($_GET[mb_strtolower(SHORT_NAME).'AC']) && !filter_var($_GET[mb_strtolower(SHORT_NAME).'AC'], FILTER_VALIDATE_BOOLEAN)) {
130
  return $this->maybeSetDebugInfo($this::NC_DEBUG_AC_GET_VAR);
131
  }
132
  if ($this->isUncacheableRequestMethod()) {
140
  if (!COMET_CACHE_FEEDS_ENABLE && $this->isFeed()) {
141
  return $this->maybeSetDebugInfo($this::NC_DEBUG_FEED_REQUEST);
142
  }
143
+ if (preg_match('/\/(?:wp\-[^\/]+|xmlrpc)\.php(?:[?]|$)/ui', $_SERVER['REQUEST_URI'])) {
144
  return $this->maybeSetDebugInfo($this::NC_DEBUG_WP_SYSTEMATICS);
145
  }
146
+ if (is_admin() || preg_match('/\/wp-admin(?:[\/?]|$)/ui', $_SERVER['REQUEST_URI'])) {
147
  return $this->maybeSetDebugInfo($this::NC_DEBUG_WP_ADMIN);
148
  }
149
+ if (is_multisite() && preg_match('/\/files(?:[\/?]|$)/ui', $_SERVER['REQUEST_URI'])) {
150
  return $this->maybeSetDebugInfo($this::NC_DEBUG_MS_FILES);
151
  }
152
  if ((!IS_PRO || !COMET_CACHE_WHEN_LOGGED_IN) && $this->isLikeUserLoggedIn()) {
158
  if (!empty($_REQUEST['preview'])) {
159
  return $this->maybeSetDebugInfo($this::NC_DEBUG_PREVIEW);
160
  }
161
+ if (COMET_CACHE_EXCLUDE_HOSTS && preg_match(COMET_CACHE_EXCLUDE_HOSTS, $_SERVER['HTTP_HOST'])) {
162
+ return $this->maybeSetDebugInfo($this::NC_DEBUG_EXCLUDED_HOSTS);
163
+ }
164
  if (COMET_CACHE_EXCLUDE_URIS && preg_match(COMET_CACHE_EXCLUDE_URIS, $_SERVER['REQUEST_URI'])) {
165
  return $this->maybeSetDebugInfo($this::NC_DEBUG_EXCLUDED_URIS);
166
  }
205
 
206
  $headers_list = $this->headersList();
207
  foreach (unserialize($headers) as $_header) {
208
+ if (!in_array($_header, $headers_list, true) && mb_stripos($_header, 'Last-Modified:') !== 0) {
209
  header($_header); // Only cacheable/safe headers are stored in the cache.
210
  }
211
  }
274
  if ((!IS_PRO || !COMET_CACHE_WHEN_LOGGED_IN) && $this->isLikeUserLoggedIn()) {
275
  return (boolean) $this->maybeSetDebugInfo($this::NC_DEBUG_IS_LIKE_LOGGED_IN_USER);
276
  }
277
+ if (!COMET_CACHE_CACHE_NONCE_VALUES && preg_match('/\b(?:_wpnonce|akismet_comment_nonce)\b/u', $cache)) {
278
  if (IS_PRO && COMET_CACHE_WHEN_LOGGED_IN && $this->isLikeUserLoggedIn()) {
279
  if (!COMET_CACHE_CACHE_NONCE_VALUES_WHEN_LOGGED_IN) {
280
  return (boolean) $this->maybeSetDebugInfo($this::NC_DEBUG_IS_LOGGED_IN_USER_NONCE);
286
  if ($this->is_404 && !COMET_CACHE_CACHE_404_REQUESTS) {
287
  return (boolean) $this->maybeSetDebugInfo($this::NC_DEBUG_404_REQUEST);
288
  }
289
+ if (mb_stripos($cache, '<body id="error-page">') !== false) {
290
  return (boolean) $this->maybeSetDebugInfo($this::NC_DEBUG_WP_ERROR_PAGE);
291
  }
292
  if (!$this->hasACacheableContentType()) {
337
 
338
  if (COMET_CACHE_DEBUGGING_ENABLE && $this->isHtmlXmlDoc($cache)) {
339
  $total_time = number_format(microtime(true) - $this->timer, 5, '.', ''); // Based on the original timer.
340
+ $via = IS_PRO && $this->isAutoCacheEngine() ? __('Auto-Cache Engine', 'comet-cache') : __('HTTP request', 'comet-cache');
341
  $cache .= "\n".'<!-- '.htmlspecialchars(sprintf(__('%1$s file path: %2$s', 'comet-cache'), NAME, str_replace(WP_CONTENT_DIR, '', $this->is_404 ? $this->cache_file_404 : $this->cache_file))).' -->';
342
+ $cache .= "\n".'<!-- '.htmlspecialchars(sprintf(__('%1$s file built for (%2$s%3$s) in %4$s seconds, on: %5$s; via %6$s.', 'comet-cache'), NAME, $this->is_404 ? '404 [error document]' : $this->salt_location, (IS_PRO && COMET_CACHE_WHEN_LOGGED_IN && $this->user_token ? '; '.sprintf(__('user token: %1$s', 'comet-cache'), $this->user_token) : ''), $total_time, date('M jS, Y @ g:i a T'), $via)).' -->';
343
  $cache .= "\n".'<!-- '.htmlspecialchars(sprintf(__('This %1$s file will auto-expire (and be rebuilt) on: %2$s (based on your configured expiration time).', 'comet-cache'), NAME, date('M jS, Y @ g:i a T', strtotime('+'.COMET_CACHE_MAX_AGE)))).' -->';
344
  }
345
  if ($this->is_404) {
src/includes/traits/Plugin/CronUtils.php CHANGED
@@ -34,7 +34,7 @@ trait CronUtils
34
  */
35
  public function checkCronSetup()
36
  {
37
- if ($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()))
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()))
src/includes/traits/Plugin/DirUtils.php CHANGED
@@ -74,10 +74,10 @@ trait DirUtils
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)) {
78
- $wp_path_rel_to_home = str_ireplace($home, '', $siteurl); /* $siteurl - $home */
79
  $pos = strripos(str_replace('\\', '/', $_SERVER['SCRIPT_FILENAME']), trailingslashit($wp_path_rel_to_home));
80
- $home_path = substr($_SERVER['SCRIPT_FILENAME'], 0, $pos);
81
  $home_path = trailingslashit($home_path);
82
  } else {
83
  $home_path = ABSPATH;
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;
src/includes/traits/Plugin/HtaccessUtils.php CHANGED
@@ -23,7 +23,7 @@ trait HtaccessUtils
23
  *
24
  * @note We keep track of this to avoid the issue described here: http://git.io/vEFIH
25
  */
26
- public $options_with_htaccess_rules = ['cdn_enable'];
27
 
28
  /**
29
  * Add template blocks to `/.htaccess` file.
@@ -36,7 +36,7 @@ trait HtaccessUtils
36
  */
37
  public function addWpHtaccess()
38
  {
39
- global $is_apache;
40
 
41
  if (!$is_apache) {
42
  return false; // Not running the Apache web server.
@@ -58,23 +58,35 @@ trait HtaccessUtils
58
  }
59
 
60
  $template_blocks = ''; // Initialize.
61
- if (is_dir($templates_dir = dirname(dirname(__DIR__)).'/templates/htaccess')) {
62
- foreach (scandir($templates_dir) as $_template_file) {
63
- switch ($_template_file) {
64
-
65
- }
 
 
 
 
 
 
 
 
 
 
 
66
  }
67
- unset($_template_file); // Housekeeping.
68
  }
 
69
 
70
  if (empty($template_blocks)) { // Do we need to add anything to htaccess?
71
  $this->closeHtaccessFile($htaccess); // No need to write to htaccess file in this case.
72
  return true; // Nothing to do, but no failures either.
73
  }
74
 
75
- $template_header = '# BEGIN '.NAME.' '.$this->htaccess_marker.' (the '.$this->htaccess_marker.' marker is required for '.NAME.'; do not remove)'."\n";
 
76
  $template_footer = '# END '.NAME.' '.$this->htaccess_marker;
77
- $htaccess['file_contents'] = $template_header.trim($template_blocks)."\n".$template_footer."\n\n".$htaccess['file_contents'];
78
 
79
  if (!$this->writeHtaccessFile($htaccess, true)) {
80
  return false; // Failure; could not write changes.
@@ -109,7 +121,7 @@ trait HtaccessUtils
109
  return false; // Failure; could not read file, create file, or invalid UTF8 encountered, file may be corrupt.
110
  }
111
 
112
- $regex = '/#\s*BEGIN\s+'.preg_quote(NAME, '/').'\s+'.$this->htaccess_marker.'.*?#\s*END\s+'.preg_quote(NAME, '/').'\s+'.$this->htaccess_marker.'\s*/is';
113
  $htaccess['file_contents'] = preg_replace($regex, '', $htaccess['file_contents']);
114
 
115
  if (!$this->writeHtaccessFile($htaccess, false)) {
@@ -181,13 +193,39 @@ trait HtaccessUtils
181
  if (empty($htaccess_marker)) {
182
  $htaccess_marker = $this->htaccess_marker;
183
  }
184
- if (stripos($htaccess_file_contents, $htaccess_marker) === false) {
185
  return false; // Htaccess marker is missing
186
  }
187
 
188
  return true; // Htaccess has the marker
189
  }
190
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
191
  /**
192
  * Gets contents of `/.htaccess` file with exclusive lock to read+write. If file doesn't exist, we attempt to create it.
193
  *
@@ -247,7 +285,7 @@ trait HtaccessUtils
247
  }
248
  $htaccess_marker = $htaccess_marker ?: $this->htaccess_marker;
249
 
250
- $_have_marker = stripos($htaccess['file_contents'], $htaccess_marker);
251
 
252
  // Note: rewind() necessary here because we fread() above.
253
  if (($require_marker && $_have_marker === false) || !rewind($htaccess['fp']) || !ftruncate($htaccess['fp'], 0) || !fwrite($htaccess['fp'], $htaccess['file_contents'])) {
23
  *
24
  * @note We keep track of this to avoid the issue described here: http://git.io/vEFIH
25
  */
26
+ public $options_with_htaccess_rules = ['cdn_enable', 'htaccess_browser_caching_enable', 'htaccess_gzip_enable', 'htaccess_enforce_canonical_urls',];
27
 
28
  /**
29
  * Add template blocks to `/.htaccess` file.
36
  */
37
  public function addWpHtaccess()
38
  {
39
+ global $is_apache; // WP global for web server checks below.
40
 
41
  if (!$is_apache) {
42
  return false; // Not running the Apache web server.
58
  }
59
 
60
  $template_blocks = ''; // Initialize.
61
+
62
+ foreach (array('gzip-enable.txt', 'access-control-allow-origin-enable.txt', 'browser-caching-enable.txt', 'canonical-urls-ts-enable.txt', 'canonical-urls-no-ts-enable.txt') as $_template) {
63
+ if (!is_file($_template_file = dirname(dirname(dirname(__FILE__))).'/templates/htaccess/'.$_template)) {
64
+ continue; // Template file missing; bypass.
65
+ } // ↑ Some files might be missing in the lite version.
66
+ elseif (!($_template_file_contents = trim(file_get_contents($_template_file)))) {
67
+ continue; // Template file empty; bypass.
68
+ } // ↑ Some files might be empty in the lite version.
69
+
70
+ switch ($_template) {
71
+ case 'gzip-enable.txt':
72
+ if ($this->options['htaccess_gzip_enable']) {
73
+ $template_blocks .= $_template_file_contents."\n\n";
74
+ } // ↑ Only if GZIP is enabled at this time.
75
+ break;
76
+
77
  }
 
78
  }
79
+ unset($_template_file); // Housekeeping
80
 
81
  if (empty($template_blocks)) { // Do we need to add anything to htaccess?
82
  $this->closeHtaccessFile($htaccess); // No need to write to htaccess file in this case.
83
  return true; // Nothing to do, but no failures either.
84
  }
85
 
86
+ $template_blocks = $this->fillReplacementCodes($template_blocks);
87
+ $template_header = '# BEGIN '.NAME.' '.$this->htaccess_marker.' (the '.$this->htaccess_marker.' marker is required for '.NAME.'; do not remove)';
88
  $template_footer = '# END '.NAME.' '.$this->htaccess_marker;
89
+ $htaccess['file_contents'] = $template_header."\n\n".trim($template_blocks)."\n\n".$template_footer."\n\n".$htaccess['file_contents'];
90
 
91
  if (!$this->writeHtaccessFile($htaccess, true)) {
92
  return false; // Failure; could not write changes.
121
  return false; // Failure; could not read file, create file, or invalid UTF8 encountered, file may be corrupt.
122
  }
123
 
124
+ $regex = '/#\s*BEGIN\s+'.preg_quote(NAME, '/').'\s+'.$this->htaccess_marker.'.*?#\s*END\s+'.preg_quote(NAME, '/').'\s+'.$this->htaccess_marker.'\s*/uis';
125
  $htaccess['file_contents'] = preg_replace($regex, '', $htaccess['file_contents']);
126
 
127
  if (!$this->writeHtaccessFile($htaccess, false)) {
193
  if (empty($htaccess_marker)) {
194
  $htaccess_marker = $this->htaccess_marker;
195
  }
196
+ if (mb_stripos($htaccess_file_contents, $htaccess_marker) === false) {
197
  return false; // Htaccess marker is missing
198
  }
199
 
200
  return true; // Htaccess has the marker
201
  }
202
 
203
+ /**
204
+ * Utility method used to update replacement codes in .htaccess templates
205
+ *
206
+ * @since 160706 Adding Apache Optimizations
207
+ *
208
+ * @param string $template_blocks .htaccess template blocks that may contain replacement codes
209
+ *
210
+ * @return string Template blocks with replacement codes filled in
211
+ */
212
+ public function fillReplacementCodes($template_blocks)
213
+ {
214
+ if (mb_stripos($template_blocks, '%%') === false) {
215
+ return $template_blocks; // No replacement codes to fill
216
+ }
217
+
218
+ $home_url = is_multisite() ? network_home_url() : home_url();
219
+ $replacement_codes = ['%%REWRITE_BASE%%' => trailingslashit(parse_url($home_url, PHP_URL_PATH))];
220
+
221
+ foreach ($replacement_codes as $_code => $_replacement) {
222
+ $template_blocks = preg_replace('/'.preg_quote($_code, '/').'/ui', $_replacement, $template_blocks);
223
+ }
224
+ unset($_code, $_replacement);
225
+
226
+ return $template_blocks;
227
+ }
228
+
229
  /**
230
  * Gets contents of `/.htaccess` file with exclusive lock to read+write. If file doesn't exist, we attempt to create it.
231
  *
285
  }
286
  $htaccess_marker = $htaccess_marker ?: $this->htaccess_marker;
287
 
288
+ $_have_marker = mb_stripos($htaccess['file_contents'], $htaccess_marker);
289
 
290
  // Note: rewind() necessary here because we fread() above.
291
  if (($require_marker && $_have_marker === false) || !rewind($htaccess['fp']) || !ftruncate($htaccess['fp'], 0) || !fwrite($htaccess['fp'], $htaccess['file_contents'])) {
src/includes/traits/Plugin/InstallUtils.php CHANGED
@@ -150,16 +150,16 @@ trait InstallUtils
150
  if (!($wp_config_file_contents_no_whitespace = php_strip_whitespace($wp_config_file))) {
151
  return ''; // Failure; file empty
152
  }
153
- if (preg_match('/\bdefine\s*\(\s*([\'"])WP_CACHE\\1\s*,\s*(?:\-?[1-9][0-9\.]*|TRUE|([\'"])(?:[^0\'"]|[^\'"]{2,})\\2)\s*\)\s*;/i', $wp_config_file_contents_no_whitespace)) {
154
  return $wp_config_file_contents; // It's already in there; no need to modify this file.
155
  }
156
  if (!($wp_config_file_contents = $this->removeWpCacheFromWpConfig())) {
157
  return ''; // Unable to remove previous value.
158
  }
159
- if (!($wp_config_file_contents = preg_replace('/^\s*(\<\?php|\<\?)\s+/i', '${1}'."\n"."define('WP_CACHE', TRUE);"."\n", $wp_config_file_contents, 1))) {
160
  return ''; // Failure; something went terribly wrong here.
161
  }
162
- if (strpos($wp_config_file_contents, "define('WP_CACHE', TRUE);") === false) {
163
  return ''; // Failure; unable to add; unexpected PHP code.
164
  }
165
  if (defined('DISALLOW_FILE_MODS') && DISALLOW_FILE_MODS) {
@@ -196,16 +196,16 @@ trait InstallUtils
196
  if (!($wp_config_file_contents_no_whitespace = php_strip_whitespace($wp_config_file))) {
197
  return ''; // Failure; file empty
198
  }
199
- if (!preg_match('/([\'"])WP_CACHE\\1/i', $wp_config_file_contents_no_whitespace)) {
200
  return $wp_config_file_contents; // Already gone.
201
  }
202
- if (preg_match('/\bdefine\s*\(\s*([\'"])WP_CACHE\\1\s*,\s*(?:0|FALSE|NULL|([\'"])0?\\2)\s*\)\s*;/i', $wp_config_file_contents_no_whitespace) && !is_writable($wp_config_file)) {
203
  return $wp_config_file_contents; // It's already disabled, and since we can't write to this file let's let this slide.
204
  }
205
- if (!($wp_config_file_contents = preg_replace('/\bdefine\s*\(\s*([\'"])WP_CACHE\\1\s*,\s*(?:\-?[0-9\.]+|TRUE|FALSE|NULL|([\'"])[^\'"]*\\2)\s*\)\s*;/i', '', $wp_config_file_contents))) {
206
  return ''; // Failure; something went terribly wrong here.
207
  }
208
- if (preg_match('/([\'"])WP_CACHE\\1/i', $wp_config_file_contents)) {
209
  return ''; // Failure; perhaps the `/wp-config.php` file contains syntax we cannot remove safely.
210
  }
211
  if (defined('DISALLOW_FILE_MODS') && DISALLOW_FILE_MODS) {
@@ -247,7 +247,7 @@ trait InstallUtils
247
  }
248
  $cache_dir = $this->cacheDir();
249
  $advanced_cache_file = WP_CONTENT_DIR.'/advanced-cache.php';
250
- $advanced_cache_check_file = $cache_dir.'/'.strtolower(SHORT_NAME).'-advanced-cache';
251
 
252
  // Fixes zero-byte advanced-cache.php bug related to migrating from ZenCache
253
  // See: <https://github.com/websharks/zencache/issues/432>
@@ -277,7 +277,7 @@ trait InstallUtils
277
  }
278
  $cache_dir = $this->cacheDir();
279
  $advanced_cache_file = WP_CONTENT_DIR.'/advanced-cache.php';
280
- $advanced_cache_check_file = $cache_dir.'/'.strtolower(SHORT_NAME).'-advanced-cache';
281
  $advanced_cache_template = dirname(dirname(__DIR__)).'/templates/advanced-cache.txt';
282
 
283
  if (is_file($advanced_cache_file) && !is_writable($advanced_cache_file)) {
@@ -306,6 +306,7 @@ trait InstallUtils
306
  $_value = (string) $_value; // Force string.
307
 
308
  switch ($_option) {
 
309
  case 'exclude_uris': // Converts to regex (caSe insensitive).
310
  case 'exclude_client_side_uris': // Converts to regex (caSe insensitive).
311
  case 'exclude_refs': // Converts to regex (caSe insensitive).
@@ -323,25 +324,24 @@ trait InstallUtils
323
  $_value = "'".$this->escSq($_value)."'";
324
  break; // Break switch handler.
325
  }
326
- $advanced_cache_contents = // Fill replacement codes.
327
- str_ireplace(
328
- [
329
- "'%%".GLOBAL_NS.'_'.$_option."%%'",
330
- "'%%".GLOBAL_NS.'_'.preg_replace('/^cache_/i', '', $_option)."%%'",
331
- ],
332
- $_value,
333
- $advanced_cache_contents
334
- );
335
  }
336
  unset($_option, $_value, $_values, $_response); // Housekeeping.
337
 
338
- if (strpos(PLUGIN_FILE, WP_CONTENT_DIR) === 0) {
339
  $plugin_file = "WP_CONTENT_DIR.'".$this->escSq(str_replace(WP_CONTENT_DIR, '', PLUGIN_FILE))."'";
340
  } else {
341
  $plugin_file = "'".$this->escSq(PLUGIN_FILE)."'"; // Full absolute path.
342
  }
343
  // Make it possible for the `advanced-cache.php` handler to find the plugin directory reliably.
344
- $advanced_cache_contents = str_ireplace("'%%".GLOBAL_NS."_PLUGIN_FILE%%'", $plugin_file, $advanced_cache_contents);
345
 
346
  // Ignore; this is created by Comet Cache; and we don't need to obey in this case.
347
  #if(defined('DISALLOW_FILE_MODS') && DISALLOW_FILE_MODS)
@@ -422,7 +422,7 @@ trait InstallUtils
422
  {
423
  $cache_dir = $this->cacheDir();
424
  $advanced_cache_file = WP_CONTENT_DIR.'/advanced-cache.php';
425
- $advanced_cache_check_file = $cache_dir.'/'.strtolower(SHORT_NAME).'-advanced-cache';
426
 
427
  if (is_file($advanced_cache_file)) {
428
  if (!is_writable($advanced_cache_file) || !unlink($advanced_cache_file)) {
@@ -468,7 +468,7 @@ trait InstallUtils
468
  return; // Skip on plugin actions.
469
  }
470
  $cache_dir = $this->cacheDir();
471
- $blog_paths_file = $cache_dir.'/'.strtolower(SHORT_NAME).'-blog-paths';
472
 
473
  if (!is_file($blog_paths_file)) {
474
  $this->updateBlogPaths();
@@ -499,7 +499,7 @@ trait InstallUtils
499
  return $value; // N/A.
500
  }
501
  $cache_dir = $this->cacheDir();
502
- $blog_paths_file = $cache_dir.'/'.strtolower(SHORT_NAME).'-blog-paths';
503
 
504
  $cache_lock = $this->cacheLock();
505
 
@@ -518,7 +518,7 @@ trait InstallUtils
518
  foreach ($paths as $_key => &$_path) {
519
  if ($_path && $_path !== '/' && $host_base_token && $host_base_token !== '/') {
520
  // Note that each `path` in the DB looks like: `[/base]/path/` (i.e., it includes base).
521
- $_path = '/'.ltrim(preg_replace('/^'.preg_quote($host_base_token, '/').'/', '', $_path), '/');
522
  }
523
  if (!$_path || $_path === '/') {
524
  unset($paths[$_key]); // Exclude main site.
150
  if (!($wp_config_file_contents_no_whitespace = php_strip_whitespace($wp_config_file))) {
151
  return ''; // Failure; file empty
152
  }
153
+ if (preg_match('/\bdefine\s*\(\s*([\'"])WP_CACHE\\1\s*,\s*(?:\-?[1-9][0-9\.]*|TRUE|([\'"])(?:[^0\'"]|[^\'"]{2,})\\2)\s*\)\s*;/ui', $wp_config_file_contents_no_whitespace)) {
154
  return $wp_config_file_contents; // It's already in there; no need to modify this file.
155
  }
156
  if (!($wp_config_file_contents = $this->removeWpCacheFromWpConfig())) {
157
  return ''; // Unable to remove previous value.
158
  }
159
+ if (!($wp_config_file_contents = preg_replace('/^\s*(\<\?php|\<\?)\s+/ui', '${1}'."\n"."define('WP_CACHE', TRUE);"."\n", $wp_config_file_contents, 1))) {
160
  return ''; // Failure; something went terribly wrong here.
161
  }
162
+ if (mb_strpos($wp_config_file_contents, "define('WP_CACHE', TRUE);") === false) {
163
  return ''; // Failure; unable to add; unexpected PHP code.
164
  }
165
  if (defined('DISALLOW_FILE_MODS') && DISALLOW_FILE_MODS) {
196
  if (!($wp_config_file_contents_no_whitespace = php_strip_whitespace($wp_config_file))) {
197
  return ''; // Failure; file empty
198
  }
199
+ if (!preg_match('/([\'"])WP_CACHE\\1/ui', $wp_config_file_contents_no_whitespace)) {
200
  return $wp_config_file_contents; // Already gone.
201
  }
202
+ if (preg_match('/\bdefine\s*\(\s*([\'"])WP_CACHE\\1\s*,\s*(?:0|FALSE|NULL|([\'"])0?\\2)\s*\)\s*;/ui', $wp_config_file_contents_no_whitespace) && !is_writable($wp_config_file)) {
203
  return $wp_config_file_contents; // It's already disabled, and since we can't write to this file let's let this slide.
204
  }
205
+ if (!($wp_config_file_contents = preg_replace('/\bdefine\s*\(\s*([\'"])WP_CACHE\\1\s*,\s*(?:\-?[0-9\.]+|TRUE|FALSE|NULL|([\'"])[^\'"]*\\2)\s*\)\s*;/ui', '', $wp_config_file_contents))) {
206
  return ''; // Failure; something went terribly wrong here.
207
  }
208
+ if (preg_match('/([\'"])WP_CACHE\\1/ui', $wp_config_file_contents)) {
209
  return ''; // Failure; perhaps the `/wp-config.php` file contains syntax we cannot remove safely.
210
  }
211
  if (defined('DISALLOW_FILE_MODS') && DISALLOW_FILE_MODS) {
247
  }
248
  $cache_dir = $this->cacheDir();
249
  $advanced_cache_file = WP_CONTENT_DIR.'/advanced-cache.php';
250
+ $advanced_cache_check_file = $cache_dir.'/'.mb_strtolower(SHORT_NAME).'-advanced-cache';
251
 
252
  // Fixes zero-byte advanced-cache.php bug related to migrating from ZenCache
253
  // See: <https://github.com/websharks/zencache/issues/432>
277
  }
278
  $cache_dir = $this->cacheDir();
279
  $advanced_cache_file = WP_CONTENT_DIR.'/advanced-cache.php';
280
+ $advanced_cache_check_file = $cache_dir.'/'.mb_strtolower(SHORT_NAME).'-advanced-cache';
281
  $advanced_cache_template = dirname(dirname(__DIR__)).'/templates/advanced-cache.txt';
282
 
283
  if (is_file($advanced_cache_file) && !is_writable($advanced_cache_file)) {
306
  $_value = (string) $_value; // Force string.
307
 
308
  switch ($_option) {
309
+ case 'exclude_hosts': // Converts to regex (caSe insensitive).
310
  case 'exclude_uris': // Converts to regex (caSe insensitive).
311
  case 'exclude_client_side_uris': // Converts to regex (caSe insensitive).
312
  case 'exclude_refs': // Converts to regex (caSe insensitive).
324
  $_value = "'".$this->escSq($_value)."'";
325
  break; // Break switch handler.
326
  }
327
+ $advanced_cache_contents = preg_replace(
328
+ [
329
+ '/'.preg_quote("'%%".GLOBAL_NS.'_'.$_option."%%'", '/').'/ui',
330
+ '/'.preg_quote("'%%".GLOBAL_NS.'_'.preg_replace('/^cache_/ui', '', $_option)."%%'", '/').'/ui',
331
+ ],
332
+ $_value,
333
+ $advanced_cache_contents
334
+ );
 
335
  }
336
  unset($_option, $_value, $_values, $_response); // Housekeeping.
337
 
338
+ if (mb_strpos(PLUGIN_FILE, WP_CONTENT_DIR) === 0) {
339
  $plugin_file = "WP_CONTENT_DIR.'".$this->escSq(str_replace(WP_CONTENT_DIR, '', PLUGIN_FILE))."'";
340
  } else {
341
  $plugin_file = "'".$this->escSq(PLUGIN_FILE)."'"; // Full absolute path.
342
  }
343
  // Make it possible for the `advanced-cache.php` handler to find the plugin directory reliably.
344
+ $advanced_cache_contents = preg_replace('/'.preg_quote("'%%".GLOBAL_NS."_PLUGIN_FILE%%'", '/').'/ui', $plugin_file, $advanced_cache_contents);
345
 
346
  // Ignore; this is created by Comet Cache; and we don't need to obey in this case.
347
  #if(defined('DISALLOW_FILE_MODS') && DISALLOW_FILE_MODS)
422
  {
423
  $cache_dir = $this->cacheDir();
424
  $advanced_cache_file = WP_CONTENT_DIR.'/advanced-cache.php';
425
+ $advanced_cache_check_file = $cache_dir.'/'.mb_strtolower(SHORT_NAME).'-advanced-cache';
426
 
427
  if (is_file($advanced_cache_file)) {
428
  if (!is_writable($advanced_cache_file) || !unlink($advanced_cache_file)) {
468
  return; // Skip on plugin actions.
469
  }
470
  $cache_dir = $this->cacheDir();
471
+ $blog_paths_file = $cache_dir.'/'.mb_strtolower(SHORT_NAME).'-blog-paths';
472
 
473
  if (!is_file($blog_paths_file)) {
474
  $this->updateBlogPaths();
499
  return $value; // N/A.
500
  }
501
  $cache_dir = $this->cacheDir();
502
+ $blog_paths_file = $cache_dir.'/'.mb_strtolower(SHORT_NAME).'-blog-paths';
503
 
504
  $cache_lock = $this->cacheLock();
505
 
518
  foreach ($paths as $_key => &$_path) {
519
  if ($_path && $_path !== '/' && $host_base_token && $host_base_token !== '/') {
520
  // Note that each `path` in the DB looks like: `[/base]/path/` (i.e., it includes base).
521
+ $_path = '/'.ltrim(preg_replace('/^'.preg_quote($host_base_token, '/').'/u', '', $_path), '/');
522
  }
523
  if (!$_path || $_path === '/') {
524
  unset($paths[$_key]); // Exclude main site.
src/includes/traits/Plugin/MenuPageUtils.php CHANGED
@@ -14,7 +14,7 @@ trait MenuPageUtils
14
  */
15
  public function enqueueAdminStyles()
16
  {
17
- if (empty($_GET['page']) || strpos($_GET['page'], GLOBAL_NS) !== 0) {
18
  return; // NOT a plugin page in the administrative area.
19
  }
20
  $deps = []; // Plugin dependencies.
@@ -31,7 +31,7 @@ trait MenuPageUtils
31
  */
32
  public function enqueueAdminScripts()
33
  {
34
- if (empty($_GET['page']) || strpos($_GET['page'], GLOBAL_NS) !== 0) {
35
  return; // NOT a plugin page in the administrative area.
36
  }
37
  $deps = ['jquery', 'chartjs']; // Plugin dependencies.
@@ -159,7 +159,7 @@ trait MenuPageUtils
159
  $current_pagenow = !empty($GLOBALS['pagenow']) ? $GLOBALS['pagenow'] : '';
160
  $current_page = !empty($_REQUEST['page']) ? $_REQUEST['page'] : '';
161
 
162
- if (strpos($current_pagenow, GLOBAL_NS) === 0 || strpos($current_page, GLOBAL_NS) === 0) {
163
  $use_icon_fill_color = $icon_colors['current'];
164
  }
165
  return str_replace(' fill="currentColor"', ' fill="'.esc_attr($use_icon_fill_color).'"', $svg);
14
  */
15
  public function enqueueAdminStyles()
16
  {
17
+ if (empty($_GET['page']) || mb_strpos($_GET['page'], GLOBAL_NS) !== 0) {
18
  return; // NOT a plugin page in the administrative area.
19
  }
20
  $deps = []; // Plugin dependencies.
31
  */
32
  public function enqueueAdminScripts()
33
  {
34
+ if (empty($_GET['page']) || mb_strpos($_GET['page'], GLOBAL_NS) !== 0) {
35
  return; // NOT a plugin page in the administrative area.
36
  }
37
  $deps = ['jquery', 'chartjs']; // Plugin dependencies.
159
  $current_pagenow = !empty($GLOBALS['pagenow']) ? $GLOBALS['pagenow'] : '';
160
  $current_page = !empty($_REQUEST['page']) ? $_REQUEST['page'] : '';
161
 
162
+ if (mb_strpos($current_pagenow, GLOBAL_NS) === 0 || mb_strpos($current_page, GLOBAL_NS) === 0) {
163
  $use_icon_fill_color = $icon_colors['current'];
164
  }
165
  return str_replace(' fill="currentColor"', ' fill="'.esc_attr($use_icon_fill_color).'"', $svg);
src/includes/traits/Plugin/NoticeUtils.php CHANGED
@@ -151,7 +151,7 @@ trait NoticeUtils
151
  }
152
  # Current URI matches a limited scope/context for this notice?
153
 
154
- if ($_notice['only_on_uris'] && !@preg_match($_notice['only_on_uris'], $_SERVER['REQUEST_URI'])) {
155
  continue; // Not in the right context at the moment; i.e., does not regex.
156
  }
157
  # If persistent, allow a site owner to dismiss.
151
  }
152
  # Current URI matches a limited scope/context for this notice?
153
 
154
+ if ($_notice['only_on_uris'] && (empty($_SERVER['REQUEST_URI']) || !@preg_match($_notice['only_on_uris'], $_SERVER['REQUEST_URI']))) {
155
  continue; // Not in the right context at the moment; i.e., does not regex.
156
  }
157
  # If persistent, allow a site owner to dismiss.
src/includes/traits/Plugin/OptionUtils.php CHANGED
@@ -35,7 +35,7 @@ trait OptionUtils
35
  unset($_key, $_value); // Housekeeping.
36
 
37
  $this->options['base_dir'] = trim($this->options['base_dir'], '\\/'." \t\n\r\0\x0B");
38
- if (!$this->options['base_dir'] || strpos(basename($this->options['base_dir']), 'wp-') === 0) {
39
  $this->options['base_dir'] = $this->default_options['base_dir'];
40
  }
41
  return $this->options; // Plugin options.
35
  unset($_key, $_value); // Housekeeping.
36
 
37
  $this->options['base_dir'] = trim($this->options['base_dir'], '\\/'." \t\n\r\0\x0B");
38
+ if (!$this->options['base_dir'] || mb_strpos(basename($this->options['base_dir']), 'wp-') === 0) {
39
  $this->options['base_dir'] = $this->default_options['base_dir'];
40
  }
41
  return $this->options; // Plugin options.
src/includes/traits/Plugin/WcpPostUtils.php CHANGED
@@ -71,7 +71,7 @@ trait WcpPostUtils
71
  }
72
  if ($post_status === 'draft' && isset($GLOBALS['pagenow'], $_POST['publish'])
73
  && is_admin() && $GLOBALS['pagenow'] === 'post.php' && current_user_can('publish_posts')
74
- && strpos(wp_get_referer(), '/post-new.php') !== false
75
  ) {
76
  $post_status = 'publish'; // A new post being published now.
77
  }
71
  }
72
  if ($post_status === 'draft' && isset($GLOBALS['pagenow'], $_POST['publish'])
73
  && is_admin() && $GLOBALS['pagenow'] === 'post.php' && current_user_can('publish_posts')
74
+ && mb_strpos(wp_get_referer(), '/post-new.php') !== false
75
  ) {
76
  $post_status = 'publish'; // A new post being published now.
77
  }
src/includes/traits/Plugin/WcpSettingUtils.php CHANGED
@@ -25,12 +25,14 @@ trait WcpSettingUtils
25
  $done = true; // Flag as having been done.
26
 
27
  if ($pagenow === 'options-general.php' && $settings_updated) {
 
28
  $counter += $this->autoClearCache();
29
  } elseif ($pagenow === 'options-reading.php' && $settings_updated) {
30
  $counter += $this->autoClearCache();
31
  } elseif ($pagenow === 'options-discussion.php' && $settings_updated) {
32
  $counter += $this->autoClearCache();
33
  } elseif ($pagenow === 'options-permalink.php' && $settings_updated) {
 
34
  $counter += $this->autoClearCache();
35
  }
36
  }
25
  $done = true; // Flag as having been done.
26
 
27
  if ($pagenow === 'options-general.php' && $settings_updated) {
28
+ $this->addWpHtaccess(); // Update .htaccess if applicable
29
  $counter += $this->autoClearCache();
30
  } elseif ($pagenow === 'options-reading.php' && $settings_updated) {
31
  $counter += $this->autoClearCache();
32
  } elseif ($pagenow === 'options-discussion.php' && $settings_updated) {
33
  $counter += $this->autoClearCache();
34
  } elseif ($pagenow === 'options-permalink.php' && $settings_updated) {
35
+ $this->addWpHtaccess(); // Update .htaccess if applicable
36
  $counter += $this->autoClearCache();
37
  }
38
  }
src/includes/traits/Plugin/WcpTermUtils.php CHANGED
@@ -54,7 +54,7 @@ trait WcpTermUtils
54
 
55
  if ($post_status === 'draft' && isset($GLOBALS['pagenow'], $_POST['publish'])
56
  && is_admin() && $GLOBALS['pagenow'] === 'post.php' && current_user_can('publish_posts')
57
- && strpos(wp_get_referer(), '/post-new.php') !== false
58
  ) {
59
  $post_status = 'publish'; // A new post being published now.
60
  }
54
 
55
  if ($post_status === 'draft' && isset($GLOBALS['pagenow'], $_POST['publish'])
56
  && is_admin() && $GLOBALS['pagenow'] === 'post.php' && current_user_can('publish_posts')
57
+ && mb_strpos(wp_get_referer(), '/post-new.php') !== false
58
  ) {
59
  $post_status = 'publish'; // A new post being published now.
60
  }
src/includes/traits/Shared/CacheDirUtils.php CHANGED
@@ -142,15 +142,15 @@ trait CacheDirUtils
142
 
143
  $cache_dir_tmp_regex = $regex; // Initialize host-specific regex pattern for the tmp directory.
144
  $cache_dir_tmp_regex = '\\/'.ltrim($cache_dir_tmp_regex, '^\\/'); // Make sure it begins with an escaped `/`.
145
- $cache_dir_tmp_regex = $this->strIreplaceOnce(preg_quote($cache_dir.'/', '/'), '', $cache_dir_tmp_regex);
146
 
147
  $cache_dir_tmp_regex = ltrim($cache_dir_tmp_regex, '^\\/');
148
- if (strpos($cache_dir_tmp_regex, '(?:\/') === 0 || strpos($cache_dir_tmp_regex, '(\/') === 0) {
149
  $cache_dir_tmp_regex = '/^'.preg_quote($cache_dir_tmp, '/').$cache_dir_tmp_regex;
150
  } else {
151
  $cache_dir_tmp_regex = '/^'.preg_quote($cache_dir_tmp.'/', '/').$cache_dir_tmp_regex;
152
  }
153
- # if(WP_DEBUG) file_put_contents(WP_CONTENT_DIR.'/'.strtolower(SHORT_NAME).'-debug.log', print_r($regex, TRUE)."\n".print_r($cache_dir_tmp_regex, TRUE)."\n\n", FILE_APPEND);
154
  // Uncomment the above line to debug regex pattern matching used by this routine; and others that call upon it.
155
 
156
  if (!rename($cache_dir, $cache_dir_tmp)) {
@@ -161,7 +161,7 @@ trait CacheDirUtils
161
  $_sub_path_name = $_resource->getSubpathname();
162
  $_path_name = $_resource->getPathname();
163
 
164
- if ($_resource_type !== 'dir' && strpos($_sub_path_name, '/') === false) {
165
  continue; // Don't delete links/files in the immediate directory; e.g. `[SHORT_NAME]-advanced-cache` or `.htaccess`, etc.
166
  // Actual `http|https/...` cache links/files are nested. Links/files in the immediate directory are for other purposes.
167
  }
@@ -269,6 +269,18 @@ trait CacheDirUtils
269
  if (!is_dir($cache_dir = $this->cacheDir())) {
270
  return $counter; // Nothing to do.
271
  }
 
 
 
 
 
 
 
 
 
 
 
 
272
  $cache_dir = $this->nDirSeps($cache_dir); // Normalize.
273
  $host_token = $current_host_token = $this->hostToken();
274
  $host_base_dir_tokens = $current_host_base_dir_tokens = $this->hostBaseDirTokens();
@@ -307,16 +319,16 @@ trait CacheDirUtils
307
 
308
  $_host_cache_dir_tmp_regex = $regex; // Initialize host-specific regex pattern for the tmp directory.
309
  $_host_cache_dir_tmp_regex = '\\/'.ltrim($_host_cache_dir_tmp_regex, '^\\/'); // Make sure it begins with an escaped `/`.
310
- $_host_cache_dir_tmp_regex = $this->strIreplaceOnce(preg_quote($_host_cache_path.'/', '/'), '', $_host_cache_dir_tmp_regex);
311
- $_host_cache_dir_tmp_regex = $this->strIreplaceOnce(preg_quote($_host_cache_dir.'/', '/'), '', $_host_cache_dir_tmp_regex);
312
 
313
  $_host_cache_dir_tmp_regex = ltrim($_host_cache_dir_tmp_regex, '^\\/');
314
- if (strpos($_host_cache_dir_tmp_regex, '(?:\/') === 0 || strpos($_host_cache_dir_tmp_regex, '(\/') === 0) {
315
  $_host_cache_dir_tmp_regex = '/^'.preg_quote($_host_cache_dir_tmp, '/').$_host_cache_dir_tmp_regex;
316
  } else {
317
  $_host_cache_dir_tmp_regex = '/^'.preg_quote($_host_cache_dir_tmp.'/', '/').$_host_cache_dir_tmp_regex;
318
  }
319
- #if(WP_DEBUG) file_put_contents(WP_CONTENT_DIR.'/'.strtolower(SHORT_NAME).'-debug.log', print_r($regex, TRUE)."\n".print_r($_host_cache_dir_tmp_regex, TRUE)."\n\n", FILE_APPEND);
320
  // Uncomment the above line to debug regex pattern matching used by this routine; and others that call upon it.
321
 
322
  if (!rename($_host_cache_dir, $_host_cache_dir_tmp)) {
@@ -327,7 +339,7 @@ trait CacheDirUtils
327
  $_sub_path_name = $_resource->getSubpathname();
328
  $_path_name = $_resource->getPathname();
329
 
330
- if ($_host_cache_dir === $cache_dir && $_resource_type !== 'dir' && strpos($_sub_path_name, '/') === false) {
331
  continue; // Don't delete links/files in the immediate directory; e.g. `[SHORT_NAME]-advanced-cache` or `.htaccess`, etc.
332
  // Actual `http|https/...` cache links/files are nested. Links/files in the immediate directory are for other purposes.
333
  }
@@ -458,10 +470,10 @@ trait CacheDirUtils
458
  $wp_content_dir = $this->nDirSeps(WP_CONTENT_DIR);
459
  $wp_content_dir_regex = preg_quote($wp_content_dir, '/');
460
 
461
- if (!preg_match('/^'.$wp_content_dir_regex.'\/[^\/]+/i', $dir)) {
462
  return $counter; // Security flag; do nothing in this case.
463
  }
464
- if (preg_match('/^'.$wp_content_dir_regex.'\/(?:mu\-plugins|themes|plugins)(?:\/|$)/i', $dir)) {
465
  return $counter; // Security flag; do nothing in this case.
466
  }
467
  /* ------- Begin lock state... ----------- */
@@ -564,10 +576,10 @@ trait CacheDirUtils
564
  $wp_content_dir = $this->nDirSeps(WP_CONTENT_DIR);
565
  $wp_content_dir_regex = preg_quote($wp_content_dir, '/');
566
 
567
- if (!preg_match('/^'.$wp_content_dir_regex.'\/[^\/]+/i', $dir)) {
568
  return $counter; // Security flag; do nothing in this case.
569
  }
570
- if (preg_match('/^'.$wp_content_dir_regex.'\/(?:mu\-plugins|themes|plugins)(?:\/|$)/i', $dir)) {
571
  return $counter; // Security flag; do nothing in this case.
572
  }
573
  clearstatcache(); // Clear stat cache to be sure we have a fresh start below.
142
 
143
  $cache_dir_tmp_regex = $regex; // Initialize host-specific regex pattern for the tmp directory.
144
  $cache_dir_tmp_regex = '\\/'.ltrim($cache_dir_tmp_regex, '^\\/'); // Make sure it begins with an escaped `/`.
145
+ $cache_dir_tmp_regex = preg_replace('/'.preg_quote(preg_quote($cache_dir.'/', '/'), '/').'/ui', '', $cache_dir_tmp_regex, 1);
146
 
147
  $cache_dir_tmp_regex = ltrim($cache_dir_tmp_regex, '^\\/');
148
+ if (mb_strpos($cache_dir_tmp_regex, '(?:\/') === 0 || mb_strpos($cache_dir_tmp_regex, '(\/') === 0) {
149
  $cache_dir_tmp_regex = '/^'.preg_quote($cache_dir_tmp, '/').$cache_dir_tmp_regex;
150
  } else {
151
  $cache_dir_tmp_regex = '/^'.preg_quote($cache_dir_tmp.'/', '/').$cache_dir_tmp_regex;
152
  }
153
+ # if(WP_DEBUG) file_put_contents(WP_CONTENT_DIR.'/'.mb_strtolower(SHORT_NAME).'-debug.log', print_r($regex, TRUE)."\n".print_r($cache_dir_tmp_regex, TRUE)."\n\n", FILE_APPEND);
154
  // Uncomment the above line to debug regex pattern matching used by this routine; and others that call upon it.
155
 
156
  if (!rename($cache_dir, $cache_dir_tmp)) {
161
  $_sub_path_name = $_resource->getSubpathname();
162
  $_path_name = $_resource->getPathname();
163
 
164
+ if ($_resource_type !== 'dir' && mb_strpos($_sub_path_name, '/') === false) {
165
  continue; // Don't delete links/files in the immediate directory; e.g. `[SHORT_NAME]-advanced-cache` or `.htaccess`, etc.
166
  // Actual `http|https/...` cache links/files are nested. Links/files in the immediate directory are for other purposes.
167
  }
269
  if (!is_dir($cache_dir = $this->cacheDir())) {
270
  return $counter; // Nothing to do.
271
  }
272
+ // On a standard installation delete from all hosts.
273
+ // See: <https://github.com/websharks/comet-cache/issues/608>
274
+ if (!is_multisite() && !$___considering_domain_mapping) {
275
+ $regex = ltrim($regex, '^\\/');
276
+
277
+ if (mb_strpos($regex, '(?:\/') === 0 || mb_strpos($regex, '(\/') === 0) {
278
+ $regex = '/^https?\/[^\/]+'.$regex;
279
+ } else {
280
+ $regex = '/^https?\/[^\/]+\/'.$regex;
281
+ }
282
+ return $this->deleteFilesFromCacheDir($regex, $check_max_age);
283
+ }
284
  $cache_dir = $this->nDirSeps($cache_dir); // Normalize.
285
  $host_token = $current_host_token = $this->hostToken();
286
  $host_base_dir_tokens = $current_host_base_dir_tokens = $this->hostBaseDirTokens();
319
 
320
  $_host_cache_dir_tmp_regex = $regex; // Initialize host-specific regex pattern for the tmp directory.
321
  $_host_cache_dir_tmp_regex = '\\/'.ltrim($_host_cache_dir_tmp_regex, '^\\/'); // Make sure it begins with an escaped `/`.
322
+ $_host_cache_dir_tmp_regex = preg_replace('/'.preg_quote(preg_quote($_host_cache_path.'/', '/'), '/').'/ui', '', $_host_cache_dir_tmp_regex, 1);
323
+ $_host_cache_dir_tmp_regex = preg_replace('/'.preg_quote(preg_quote($_host_cache_dir.'/', '/'), '/').'/ui', '', $_host_cache_dir_tmp_regex, 1);
324
 
325
  $_host_cache_dir_tmp_regex = ltrim($_host_cache_dir_tmp_regex, '^\\/');
326
+ if (mb_strpos($_host_cache_dir_tmp_regex, '(?:\/') === 0 || mb_strpos($_host_cache_dir_tmp_regex, '(\/') === 0) {
327
  $_host_cache_dir_tmp_regex = '/^'.preg_quote($_host_cache_dir_tmp, '/').$_host_cache_dir_tmp_regex;
328
  } else {
329
  $_host_cache_dir_tmp_regex = '/^'.preg_quote($_host_cache_dir_tmp.'/', '/').$_host_cache_dir_tmp_regex;
330
  }
331
+ #if(WP_DEBUG) file_put_contents(WP_CONTENT_DIR.'/'.mb_strtolower(SHORT_NAME).'-debug.log', print_r($regex, TRUE)."\n".print_r($_host_cache_dir_tmp_regex, TRUE)."\n\n", FILE_APPEND);
332
  // Uncomment the above line to debug regex pattern matching used by this routine; and others that call upon it.
333
 
334
  if (!rename($_host_cache_dir, $_host_cache_dir_tmp)) {
339
  $_sub_path_name = $_resource->getSubpathname();
340
  $_path_name = $_resource->getPathname();
341
 
342
+ if ($_host_cache_dir === $cache_dir && $_resource_type !== 'dir' && mb_strpos($_sub_path_name, '/') === false) {
343
  continue; // Don't delete links/files in the immediate directory; e.g. `[SHORT_NAME]-advanced-cache` or `.htaccess`, etc.
344
  // Actual `http|https/...` cache links/files are nested. Links/files in the immediate directory are for other purposes.
345
  }
470
  $wp_content_dir = $this->nDirSeps(WP_CONTENT_DIR);
471
  $wp_content_dir_regex = preg_quote($wp_content_dir, '/');
472
 
473
+ if (!preg_match('/^'.$wp_content_dir_regex.'\/[^\/]+/ui', $dir)) {
474
  return $counter; // Security flag; do nothing in this case.
475
  }
476
+ if (preg_match('/^'.$wp_content_dir_regex.'\/(?:mu\-plugins|themes|plugins)(?:\/|$)/ui', $dir)) {
477
  return $counter; // Security flag; do nothing in this case.
478
  }
479
  /* ------- Begin lock state... ----------- */
576
  $wp_content_dir = $this->nDirSeps(WP_CONTENT_DIR);
577
  $wp_content_dir_regex = preg_quote($wp_content_dir, '/');
578
 
579
+ if (!preg_match('/^'.$wp_content_dir_regex.'\/[^\/]+/ui', $dir)) {
580
  return $counter; // Security flag; do nothing in this case.
581
  }
582
+ if (preg_match('/^'.$wp_content_dir_regex.'\/(?:mu\-plugins|themes|plugins)(?:\/|$)/ui', $dir)) {
583
  return $counter; // Security flag; do nothing in this case.
584
  }
585
  clearstatcache(); // Clear stat cache to be sure we have a fresh start below.
src/includes/traits/Shared/CachePathUtils.php CHANGED
@@ -94,7 +94,7 @@ trait CachePathUtils
94
  $host_base_dir_tokens = $this->hostBaseDirTokens(false, $is_url_domain_mapped, !empty($url_parts['path']) ? $url_parts['path'] : '/');
95
 
96
  $is_a_multisite_base_dir = $is_multisite && $host_base_dir_tokens && $host_base_dir_tokens !== '/' // Check?
97
- && stripos(!empty($url_parts['path']) ? rtrim($url_parts['path'], '/').'/' : '/', $host_base_dir_tokens) === 0;
98
 
99
  $is_a_multisite_base_dir_root = $is_multisite && $is_a_multisite_base_dir // Save time by using the previous check here.
100
  && strcasecmp(trim($host_base_dir_tokens, '/'), trim(!empty($url_parts['path']) ? $url_parts['path'] : '/', '/')) === 0;
@@ -110,7 +110,7 @@ trait CachePathUtils
110
  // Put multisite sub-roots into a host directory of their own.
111
  // e.g., `example-com[[-base]-child1]` instead of `example-com`.
112
  if ($is_a_multisite_base_dir && $host_base_dir_tokens && $host_base_dir_tokens !== '/') {
113
- $host_base_dir_suffix = preg_replace('/[^a-z0-9.]/i', '-', rtrim($host_base_dir_tokens, '/'));
114
  $cache_path = rtrim($cache_path, '/').$host_base_dir_suffix.'/';
115
  }
116
  }
@@ -133,7 +133,7 @@ trait CachePathUtils
133
  $url_parts['path'] = '/lp-'.sha1($url_parts['path']).'/';
134
  }
135
  } // Now add the path and check for a possible root `index/` suffix.
136
- if (!empty($url_parts['path']) && strlen($url_parts['path'] = trim($url_parts['path'], '\\/'." \t\n\r\0\x0B"))) {
137
  $cache_path .= $url_parts['path'].'/'; // Add the path as it exists.
138
 
139
  if (!($flags & $this::CACHE_PATH_NO_PATH_INDEX) && $is_multisite && $is_a_multisite_base_dir_root) {
@@ -148,7 +148,7 @@ trait CachePathUtils
148
  if ($this->isExtensionLoaded('mbstring') && mb_check_encoding($cache_path, 'UTF-8')) {
149
  $cache_path = mb_strtolower($cache_path, 'UTF-8');
150
  }
151
- $cache_path = str_replace('.', '-', strtolower($cache_path));
152
 
153
  if (!($flags & $this::CACHE_PATH_NO_QUV)) {
154
  if (!($flags & $this::CACHE_PATH_NO_QUERY)) {
@@ -167,14 +167,14 @@ trait CachePathUtils
167
  }
168
  }
169
  }
170
- $cache_path = trim(preg_replace(['/\/+/', '/\.+/'], ['/', '.'], $cache_path), '/');
171
 
172
  if ($flags & $this::CACHE_PATH_ALLOW_WD_REGEX) {
173
- $cache_path = preg_replace('/[^a-z0-9\/.*\^$]/i', '-', $cache_path);
174
  } elseif ($flags & $this::CACHE_PATH_ALLOW_WILDCARDS) {
175
- $cache_path = preg_replace('/[^a-z0-9\/.*]/i', '-', $cache_path);
176
  } else {
177
- $cache_path = preg_replace('/[^a-z0-9\/.]/i', '-', $cache_path);
178
  }
179
  if (!($flags & $this::CACHE_PATH_NO_EXT)) {
180
  $cache_path .= '.html';
@@ -249,7 +249,7 @@ trait CachePathUtils
249
  $host_cache_path = $this->buildCachePath($host_url, '', '', $flags);
250
 
251
  $cache_path = $this->buildCachePath($url, '', '', $flags);
252
- $relative_cache_path = preg_replace('/^'.preg_quote($host_cache_path, '/').'(?:\/|$)/i', '', $cache_path);
253
 
254
  $abs_relative_cache_path = isset($relative_cache_path[0]) ? '/'.$relative_cache_path : '';
255
  $abs_relative_cache_path_regex = isset($abs_relative_cache_path[0]) ? preg_quote($abs_relative_cache_path, '/') : '';
@@ -321,7 +321,7 @@ trait CachePathUtils
321
  foreach ($uri_patterns as $_key => &$_uri_pattern) {
322
  if (($_uri_pattern = trim($_uri_pattern, '^$'))) {
323
  $_cache_path = $this->buildCachePath($host_url.'/'.trim($_uri_pattern, '/'), '', '', $flags);
324
- $_relative_cache_path = preg_replace('/^'.preg_quote($host_cache_path, '/').'(?:\/|$)/i', '', $_cache_path);
325
  $_uri_pattern = $this->wdRegexToActualRegexFrag($_relative_cache_path);
326
  }
327
  if (!$_uri_pattern) {
94
  $host_base_dir_tokens = $this->hostBaseDirTokens(false, $is_url_domain_mapped, !empty($url_parts['path']) ? $url_parts['path'] : '/');
95
 
96
  $is_a_multisite_base_dir = $is_multisite && $host_base_dir_tokens && $host_base_dir_tokens !== '/' // Check?
97
+ && mb_stripos(!empty($url_parts['path']) ? rtrim($url_parts['path'], '/').'/' : '/', $host_base_dir_tokens) === 0;
98
 
99
  $is_a_multisite_base_dir_root = $is_multisite && $is_a_multisite_base_dir // Save time by using the previous check here.
100
  && strcasecmp(trim($host_base_dir_tokens, '/'), trim(!empty($url_parts['path']) ? $url_parts['path'] : '/', '/')) === 0;
110
  // Put multisite sub-roots into a host directory of their own.
111
  // e.g., `example-com[[-base]-child1]` instead of `example-com`.
112
  if ($is_a_multisite_base_dir && $host_base_dir_tokens && $host_base_dir_tokens !== '/') {
113
+ $host_base_dir_suffix = preg_replace('/[^a-z0-9.]/ui', '-', rtrim($host_base_dir_tokens, '/'));
114
  $cache_path = rtrim($cache_path, '/').$host_base_dir_suffix.'/';
115
  }
116
  }
133
  $url_parts['path'] = '/lp-'.sha1($url_parts['path']).'/';
134
  }
135
  } // Now add the path and check for a possible root `index/` suffix.
136
+ if (!empty($url_parts['path']) && mb_strlen($url_parts['path'] = trim($url_parts['path'], '\\/'." \t\n\r\0\x0B"))) {
137
  $cache_path .= $url_parts['path'].'/'; // Add the path as it exists.
138
 
139
  if (!($flags & $this::CACHE_PATH_NO_PATH_INDEX) && $is_multisite && $is_a_multisite_base_dir_root) {
148
  if ($this->isExtensionLoaded('mbstring') && mb_check_encoding($cache_path, 'UTF-8')) {
149
  $cache_path = mb_strtolower($cache_path, 'UTF-8');
150
  }
151
+ $cache_path = str_replace('.', '-', mb_strtolower($cache_path));
152
 
153
  if (!($flags & $this::CACHE_PATH_NO_QUV)) {
154
  if (!($flags & $this::CACHE_PATH_NO_QUERY)) {
167
  }
168
  }
169
  }
170
+ $cache_path = trim(preg_replace(['/\/+/u', '/\.+/u'], ['/', '.'], $cache_path), '/');
171
 
172
  if ($flags & $this::CACHE_PATH_ALLOW_WD_REGEX) {
173
+ $cache_path = preg_replace('/[^a-z0-9\/.*\^$]/ui', '-', $cache_path);
174
  } elseif ($flags & $this::CACHE_PATH_ALLOW_WILDCARDS) {
175
+ $cache_path = preg_replace('/[^a-z0-9\/.*]/ui', '-', $cache_path);
176
  } else {
177
+ $cache_path = preg_replace('/[^a-z0-9\/.]/ui', '-', $cache_path);
178
  }
179
  if (!($flags & $this::CACHE_PATH_NO_EXT)) {
180
  $cache_path .= '.html';
249
  $host_cache_path = $this->buildCachePath($host_url, '', '', $flags);
250
 
251
  $cache_path = $this->buildCachePath($url, '', '', $flags);
252
+ $relative_cache_path = preg_replace('/^'.preg_quote($host_cache_path, '/').'(?:\/|$)/ui', '', $cache_path);
253
 
254
  $abs_relative_cache_path = isset($relative_cache_path[0]) ? '/'.$relative_cache_path : '';
255
  $abs_relative_cache_path_regex = isset($abs_relative_cache_path[0]) ? preg_quote($abs_relative_cache_path, '/') : '';
321
  foreach ($uri_patterns as $_key => &$_uri_pattern) {
322
  if (($_uri_pattern = trim($_uri_pattern, '^$'))) {
323
  $_cache_path = $this->buildCachePath($host_url.'/'.trim($_uri_pattern, '/'), '', '', $flags);
324
+ $_relative_cache_path = preg_replace('/^'.preg_quote($host_cache_path, '/').'(?:\/|$)/ui', '', $_cache_path);
325
  $_uri_pattern = $this->wdRegexToActualRegexFrag($_relative_cache_path);
326
  }
327
  if (!$_uri_pattern) {
src/includes/traits/Shared/ConditionalUtils.php CHANGED
@@ -73,7 +73,7 @@ trait ConditionalUtils
73
  return $is = true;
74
  }
75
  if (!empty($_SERVER['REQUEST_METHOD']) && is_string($_SERVER['REQUEST_METHOD'])) {
76
- if (in_array(strtoupper($_SERVER['REQUEST_METHOD']), ['POST', 'PUT', 'DELETE'], true)) {
77
  return $is = true;
78
  }
79
  }
@@ -96,9 +96,9 @@ trait ConditionalUtils
96
  }
97
  if (!empty($_GET) || !empty($_SERVER['QUERY_STRING'])) {
98
  $_get_count = !empty($_GET) ? count($_GET) : 0;
99
- $is_abc_only = $_get_count === 1 && isset($_GET[strtolower(SHORT_NAME).'ABC']);
100
  $is_nginx_q_only = $_get_count === 1 && isset($_GET['q']) && $this->isNginx();
101
- $is_ac_get_var_true = isset($_GET[strtolower(SHORT_NAME).'AC']) && filter_var($_GET[strtolower(SHORT_NAME).'AC'], FILTER_VALIDATE_BOOLEAN);
102
 
103
  if (!$is_abc_only && !$is_nginx_q_only && !$is_ac_get_var_true) {
104
  return $is = true;
@@ -125,7 +125,7 @@ trait ConditionalUtils
125
  return $is = true;
126
  }
127
  if (!empty($_SERVER['REQUEST_METHOD']) && is_string($_SERVER['REQUEST_METHOD'])) {
128
- if (!in_array(strtoupper($_SERVER['REQUEST_METHOD']), ['GET'], true)) {
129
  return $is = true;
130
  }
131
  }
@@ -191,7 +191,7 @@ trait ConditionalUtils
191
  if (defined('LOCALHOST')) {
192
  return $is = (boolean) LOCALHOST;
193
  }
194
- if (preg_match('/\b(?:localhost|127\.0\.0\.1)\b/i', $this->hostToken())) {
195
  return $is = true;
196
  }
197
  return $is = false;
@@ -241,10 +241,10 @@ trait ConditionalUtils
241
  if (!is_null($is = &$this->staticKey('isHtmlXmlDoc', $doc_hash))) {
242
  return $is; // Already cached this.
243
  }
244
- if (stripos($doc, '</html>') !== false) {
245
  return $is = true;
246
  }
247
- if (stripos($doc, '<?xml') === 0) {
248
  return $is = true;
249
  }
250
  return $is = false;
@@ -267,14 +267,14 @@ trait ConditionalUtils
267
  return $is; // Already cached this.
268
  }
269
  foreach ($this->headersList() as $_key => $_header) {
270
- if (stripos($_header, 'Content-Type:') === 0) {
271
  $content_type = $_header; // Last one.
272
  }
273
  }
274
  unset($_key, $_header); // Housekeeping.
275
 
276
- if (isset($content_type[0]) && stripos($content_type, 'html') === false
277
- && stripos($content_type, 'xml') === false && stripos($content_type, GLOBAL_NS) === false
278
  ) {
279
  return $is = false; // Do NOT cache data sent by scripts serving other MIME types.
280
  }
@@ -301,7 +301,7 @@ trait ConditionalUtils
301
  return $is = false; // A non-2xx & non-404 status code.
302
  }
303
  foreach ($this->headersList() as $_key => $_header) {
304
- if (preg_match('/^(?:Retry\-After\:\s+(?P<retry>.+)|Status\:\s+(?P<status>[0-9]+)|HTTP\/[0-9]+(?:\.[0-9]+)?\s+(?P<http_status>[0-9]+))/i', $_header, $_m)) {
305
  if (!empty($_m['retry']) || (!empty($_m['status']) && $_m['status'][0] !== '2' && $_m['status'] !== '404')
306
  || (!empty($_m['http_status']) && $_m['http_status'][0] !== '2' && $_m['http_status'] !== '404')
307
  ) {
@@ -358,10 +358,10 @@ trait ConditionalUtils
358
  $disabled_functions = []; // Initialize disabled/blacklisted functions.
359
 
360
  if (($disable_functions = trim(ini_get('disable_functions')))) {
361
- $disabled_functions = array_merge($disabled_functions, preg_split('/[\s;,]+/', strtolower($disable_functions), -1, PREG_SPLIT_NO_EMPTY));
362
  }
363
  if (($blacklist_functions = trim(ini_get('suhosin.executor.func.blacklist')))) {
364
- $disabled_functions = array_merge($disabled_functions, preg_split('/[\s;,]+/', strtolower($blacklist_functions), -1, PREG_SPLIT_NO_EMPTY));
365
  }
366
  if (filter_var(ini_get('suhosin.executor.disable_eval'), FILTER_VALIDATE_BOOLEAN)) {
367
  $disabled_functions = array_merge($disabled_functions, ['eval']);
@@ -372,7 +372,7 @@ trait ConditionalUtils
372
  return $is = false; // Not possible.
373
  }
374
  }
375
- if ($disabled_functions && in_array(strtolower($function), $disabled_functions, true)) {
376
  return $is = false; // Not possible.
377
  }
378
  return $is = true;
73
  return $is = true;
74
  }
75
  if (!empty($_SERVER['REQUEST_METHOD']) && is_string($_SERVER['REQUEST_METHOD'])) {
76
+ if (in_array(mb_strtoupper($_SERVER['REQUEST_METHOD']), ['POST', 'PUT', 'DELETE'], true)) {
77
  return $is = true;
78
  }
79
  }
96
  }
97
  if (!empty($_GET) || !empty($_SERVER['QUERY_STRING'])) {
98
  $_get_count = !empty($_GET) ? count($_GET) : 0;
99
+ $is_abc_only = $_get_count === 1 && isset($_GET[mb_strtolower(SHORT_NAME).'ABC']);
100
  $is_nginx_q_only = $_get_count === 1 && isset($_GET['q']) && $this->isNginx();
101
+ $is_ac_get_var_true = isset($_GET[mb_strtolower(SHORT_NAME).'AC']) && filter_var($_GET[mb_strtolower(SHORT_NAME).'AC'], FILTER_VALIDATE_BOOLEAN);
102
 
103
  if (!$is_abc_only && !$is_nginx_q_only && !$is_ac_get_var_true) {
104
  return $is = true;
125
  return $is = true;
126
  }
127
  if (!empty($_SERVER['REQUEST_METHOD']) && is_string($_SERVER['REQUEST_METHOD'])) {
128
+ if (!in_array(mb_strtoupper($_SERVER['REQUEST_METHOD']), ['GET'], true)) {
129
  return $is = true;
130
  }
131
  }
191
  if (defined('LOCALHOST')) {
192
  return $is = (boolean) LOCALHOST;
193
  }
194
+ if (preg_match('/\b(?:localhost|127\.0\.0\.1)\b/ui', $this->hostToken())) {
195
  return $is = true;
196
  }
197
  return $is = false;
241
  if (!is_null($is = &$this->staticKey('isHtmlXmlDoc', $doc_hash))) {
242
  return $is; // Already cached this.
243
  }
244
+ if (mb_stripos($doc, '</html>') !== false) {
245
  return $is = true;
246
  }
247
+ if (mb_stripos($doc, '<?xml') === 0) {
248
  return $is = true;
249
  }
250
  return $is = false;
267
  return $is; // Already cached this.
268
  }
269
  foreach ($this->headersList() as $_key => $_header) {
270
+ if (mb_stripos($_header, 'Content-Type:') === 0) {
271
  $content_type = $_header; // Last one.
272
  }
273
  }
274
  unset($_key, $_header); // Housekeeping.
275
 
276
+ if (isset($content_type[0]) && mb_stripos($content_type, 'html') === false
277
+ && mb_stripos($content_type, 'xml') === false && mb_stripos($content_type, GLOBAL_NS) === false
278
  ) {
279
  return $is = false; // Do NOT cache data sent by scripts serving other MIME types.
280
  }
301
  return $is = false; // A non-2xx & non-404 status code.
302
  }
303
  foreach ($this->headersList() as $_key => $_header) {
304
+ if (preg_match('/^(?:Retry\-After\:\s+(?P<retry>.+)|Status\:\s+(?P<status>[0-9]+)|HTTP\/[0-9]+(?:\.[0-9]+)?\s+(?P<http_status>[0-9]+))/ui', $_header, $_m)) {
305
  if (!empty($_m['retry']) || (!empty($_m['status']) && $_m['status'][0] !== '2' && $_m['status'] !== '404')
306
  || (!empty($_m['http_status']) && $_m['http_status'][0] !== '2' && $_m['http_status'] !== '404')
307
  ) {
358
  $disabled_functions = []; // Initialize disabled/blacklisted functions.
359
 
360
  if (($disable_functions = trim(ini_get('disable_functions')))) {
361
+ $disabled_functions = array_merge($disabled_functions, preg_split('/[\s;,]+/', mb_strtolower($disable_functions), -1, PREG_SPLIT_NO_EMPTY));
362
  }
363
  if (($blacklist_functions = trim(ini_get('suhosin.executor.func.blacklist')))) {
364
+ $disabled_functions = array_merge($disabled_functions, preg_split('/[\s;,]+/', mb_strtolower($blacklist_functions), -1, PREG_SPLIT_NO_EMPTY));
365
  }
366
  if (filter_var(ini_get('suhosin.executor.disable_eval'), FILTER_VALIDATE_BOOLEAN)) {
367
  $disabled_functions = array_merge($disabled_functions, ['eval']);
372
  return $is = false; // Not possible.
373
  }
374
  }
375
+ if ($disabled_functions && in_array(mb_strtolower($function), $disabled_functions, true)) {
376
  return $is = false; // Not possible.
377
  }
378
  return $is = true;
src/includes/traits/Shared/DomainMappingUtils.php CHANGED
@@ -74,7 +74,7 @@ trait DomainMappingUtils
74
  if (empty($url_parts['host'])) {
75
  return $original_url; // Not possible.
76
  }
77
- $blog_domain = strtolower($url_parts['host']); // In the unfiltered URL.
78
  $blog_path = $this->hostDirToken(false, false, !empty($url_parts['path']) ? $url_parts['path'] : '/');
79
 
80
  if (!($blog_id = (integer) get_blog_id_from_url($blog_domain, $blog_path))) {
@@ -86,7 +86,7 @@ trait DomainMappingUtils
86
  $url_parts['host'] = $domain; // Filter the URL now.
87
  if (!empty($url_parts['path']) && $url_parts['path'] !== '/') {
88
  if (($host_base_dir_tokens = trim($this->hostBaseDirTokens(false, false, $url_parts['path']), '/'))) {
89
- $url_parts['path'] = preg_replace('/^\/'.preg_quote($host_base_dir_tokens, '/').'(\/|$)/i', '${1}', $url_parts['path']);
90
  }
91
  }
92
  return $url = $this->unParseUrl($url_parts);
@@ -159,9 +159,9 @@ trait DomainMappingUtils
159
  if (!$url && !$domain && ($blog_details = $this->blogDetails())) {
160
  $domain = $blog_details->domain;
161
  }
162
- $domain = strtolower(preg_replace('/^www\./i', '', $domain));
163
 
164
- if (!$domain || strpos($domain, '.') === false) {
165
  return 0; // Not possible.
166
  }
167
  if (!is_null($blog_id = &$this->staticKey('domainMappingBlogId', $domain))) {
@@ -217,7 +217,7 @@ trait DomainMappingUtils
217
  if (!$enforcing_primary_domain) {
218
  if ($this->isDomainMapping() === $blog_id) {
219
  $domain = $this->hostToken();
220
- $domain = preg_replace('/^www\./i', '', $domain);
221
  $domain = (string) $wpdb->get_var('SELECT `domain` FROM `'.esc_sql($wpdb->base_prefix.'domain_mapping').'` WHERE `blog_id` = \''.esc_sql($blog_id).'\' AND `domain` IN(\''.esc_sql('www.'.$domain).'\', \''.esc_sql($domain).'\') ORDER BY CHAR_LENGTH(`domain`) DESC LIMIT 1');
222
  } elseif (($domains = $this->domainMappingBlogDomains($blog_id))) {
223
  $domain = $domains[0]; // Use the first of all possible domains.
@@ -230,7 +230,7 @@ trait DomainMappingUtils
230
  }
231
  $wpdb->suppress_errors($suppressing_errors); // Restore.
232
 
233
- return $domain = strtolower((string) $domain);
234
  }
235
 
236
  /**
@@ -272,6 +272,6 @@ trait DomainMappingUtils
272
  }
273
  $wpdb->suppress_errors($suppressing_errors); // Restore.
274
 
275
- return $domains = array_unique(array_map('strtolower', (array) $domains));
276
  }
277
  }
74
  if (empty($url_parts['host'])) {
75
  return $original_url; // Not possible.
76
  }
77
+ $blog_domain = mb_strtolower($url_parts['host']); // In the unfiltered URL.
78
  $blog_path = $this->hostDirToken(false, false, !empty($url_parts['path']) ? $url_parts['path'] : '/');
79
 
80
  if (!($blog_id = (integer) get_blog_id_from_url($blog_domain, $blog_path))) {
86
  $url_parts['host'] = $domain; // Filter the URL now.
87
  if (!empty($url_parts['path']) && $url_parts['path'] !== '/') {
88
  if (($host_base_dir_tokens = trim($this->hostBaseDirTokens(false, false, $url_parts['path']), '/'))) {
89
+ $url_parts['path'] = preg_replace('/^\/'.preg_quote($host_base_dir_tokens, '/').'(\/|$)/ui', '${1}', $url_parts['path']);
90
  }
91
  }
92
  return $url = $this->unParseUrl($url_parts);
159
  if (!$url && !$domain && ($blog_details = $this->blogDetails())) {
160
  $domain = $blog_details->domain;
161
  }
162
+ $domain = mb_strtolower(preg_replace('/^www\./ui', '', $domain));
163
 
164
+ if (!$domain || mb_strpos($domain, '.') === false) {
165
  return 0; // Not possible.
166
  }
167
  if (!is_null($blog_id = &$this->staticKey('domainMappingBlogId', $domain))) {
217
  if (!$enforcing_primary_domain) {
218
  if ($this->isDomainMapping() === $blog_id) {
219
  $domain = $this->hostToken();
220
+ $domain = preg_replace('/^www\./ui', '', $domain);
221
  $domain = (string) $wpdb->get_var('SELECT `domain` FROM `'.esc_sql($wpdb->base_prefix.'domain_mapping').'` WHERE `blog_id` = \''.esc_sql($blog_id).'\' AND `domain` IN(\''.esc_sql('www.'.$domain).'\', \''.esc_sql($domain).'\') ORDER BY CHAR_LENGTH(`domain`) DESC LIMIT 1');
222
  } elseif (($domains = $this->domainMappingBlogDomains($blog_id))) {
223
  $domain = $domains[0]; // Use the first of all possible domains.
230
  }
231
  $wpdb->suppress_errors($suppressing_errors); // Restore.
232
 
233
+ return $domain = mb_strtolower((string) $domain);
234
  }
235
 
236
  /**
272
  }
273
  $wpdb->suppress_errors($suppressing_errors); // Restore.
274
 
275
+ return $domains = array_unique(array_map('mb_strtolower', (array) $domains));
276
  }
277
  }
src/includes/traits/Shared/FsUtils.php CHANGED
@@ -23,21 +23,21 @@ trait FsUtils
23
  if (!isset($dir_file[0])) {
24
  return ''; // Catch empty string.
25
  }
26
- if (strpos($dir_file, '://' !== false)) {
27
- if (preg_match('/^(?P<stream_wrapper>[a-zA-Z0-9]+)\:\/\//', $dir_file, $stream_wrapper)) {
28
- $dir_file = preg_replace('/^(?P<stream_wrapper>[a-zA-Z0-9]+)\:\/\//', '', $dir_file);
29
  }
30
  }
31
- if (strpos($dir_file, ':' !== false)) {
32
- if (preg_match('/^(?P<drive_letter>[a-zA-Z])\:[\/\\\\]/', $dir_file)) {
33
- $dir_file = preg_replace_callback('/^(?P<drive_letter>[a-zA-Z])\:[\/\\\\]/', create_function('$m', 'return strtoupper($m[0]);'), $dir_file);
34
  }
35
  }
36
- $dir_file = preg_replace('/\/+/', '/', str_replace([DIRECTORY_SEPARATOR, '\\', '/'], '/', $dir_file));
37
  $dir_file = ($allow_trailing_slash) ? $dir_file : rtrim($dir_file, '/'); // Strip trailing slashes.
38
 
39
  if (!empty($stream_wrapper[0])) {
40
- $dir_file = strtolower($stream_wrapper[0]).$dir_file;
41
  }
42
  return $dir_file; // Normalized now.
43
  }
@@ -73,10 +73,10 @@ trait FsUtils
73
  if (!empty($_SERVER['TMP'])) {
74
  $possible_dirs[] = (string) $_SERVER['TMP'];
75
  }
76
- if (stripos(PHP_OS, 'win') === 0) {
77
  $possible_dirs[] = 'C:/Temp';
78
  }
79
- if (stripos(PHP_OS, 'win') !== 0) {
80
  $possible_dirs[] = '/tmp';
81
  }
82
  if (defined('WP_CONTENT_DIR')) {
@@ -204,7 +204,7 @@ trait FsUtils
204
  return (float) 0;
205
  }
206
  $value = (float) $_m['value'];
207
- $modifier = strtolower($_m['modifier']);
208
  unset($_m); // Housekeeping.
209
 
210
  switch ($modifier) {
@@ -268,7 +268,7 @@ trait FsUtils
268
  if (!$dir || !is_dir($dir)) {
269
  return $stats; // Not possible.
270
  }
271
- $short_name_lc = strtolower(SHORT_NAME); // Once only.
272
 
273
  foreach ($this->dirRegexIteration($dir, $regex) as $_resource) {
274
  $_resource_sub_path = $_resource->getSubpathname();
@@ -280,7 +280,7 @@ trait FsUtils
280
  if ($_resource_basename === '.htaccess') {
281
  continue; // Ignore `.htaccess`.
282
  }
283
- if (stripos($_resource_sub_path, $short_name_lc.'-') === 0) {
284
  continue; // Ignore [SHORT_NAME] files in base.
285
  }
286
  switch ($_resource->getType()) { // `link`, `file`, `dir`.
23
  if (!isset($dir_file[0])) {
24
  return ''; // Catch empty string.
25
  }
26
+ if (mb_strpos($dir_file, '://' !== false)) {
27
+ if (preg_match('/^(?P<stream_wrapper>[a-zA-Z0-9]+)\:\/\//u', $dir_file, $stream_wrapper)) {
28
+ $dir_file = preg_replace('/^(?P<stream_wrapper>[a-zA-Z0-9]+)\:\/\//u', '', $dir_file);
29
  }
30
  }
31
+ if (mb_strpos($dir_file, ':' !== false)) {
32
+ if (preg_match('/^(?P<drive_letter>[a-zA-Z])\:[\/\\\\]/u', $dir_file)) {
33
+ $dir_file = preg_replace_callback('/^(?P<drive_letter>[a-zA-Z])\:[\/\\\\]/u', create_function('$m', 'return mb_strtoupper($m[0]);'), $dir_file);
34
  }
35
  }
36
+ $dir_file = preg_replace('/\/+/u', '/', str_replace([DIRECTORY_SEPARATOR, '\\', '/'], '/', $dir_file));
37
  $dir_file = ($allow_trailing_slash) ? $dir_file : rtrim($dir_file, '/'); // Strip trailing slashes.
38
 
39
  if (!empty($stream_wrapper[0])) {
40
+ $dir_file = mb_strtolower($stream_wrapper[0]).$dir_file;
41
  }
42
  return $dir_file; // Normalized now.
43
  }
73
  if (!empty($_SERVER['TMP'])) {
74
  $possible_dirs[] = (string) $_SERVER['TMP'];
75
  }
76
+ if (mb_stripos(PHP_OS, 'win') === 0) {
77
  $possible_dirs[] = 'C:/Temp';
78
  }
79
+ if (mb_stripos(PHP_OS, 'win') !== 0) {
80
  $possible_dirs[] = '/tmp';
81
  }
82
  if (defined('WP_CONTENT_DIR')) {
204
  return (float) 0;
205
  }
206
  $value = (float) $_m['value'];
207
+ $modifier = mb_strtolower($_m['modifier']);
208
  unset($_m); // Housekeeping.
209
 
210
  switch ($modifier) {
268
  if (!$dir || !is_dir($dir)) {
269
  return $stats; // Not possible.
270
  }
271
+ $short_name_lc = mb_strtolower(SHORT_NAME); // Once only.
272
 
273
  foreach ($this->dirRegexIteration($dir, $regex) as $_resource) {
274
  $_resource_sub_path = $_resource->getSubpathname();
280
  if ($_resource_basename === '.htaccess') {
281
  continue; // Ignore `.htaccess`.
282
  }
283
+ if (mb_stripos($_resource_sub_path, $short_name_lc.'-') === 0) {
284
  continue; // Ignore [SHORT_NAME] files in base.
285
  }
286
  switch ($_resource->getType()) { // `link`, `file`, `dir`.
src/includes/traits/Shared/HookUtils.php CHANGED
@@ -60,8 +60,8 @@ trait HookUtils
60
  public function addHook($hook, $function, $priority = 10, $accepted_args = 1)
61
  {
62
  $hook = (string) $hook;
63
- if (stripos($hook, 'zencache') === 0) {
64
- $hook = GLOBAL_NS.substr($hook, strlen('zencache'));
65
  }
66
  $priority = (integer) $priority;
67
  $accepted_args = max(0, (integer) $accepted_args);
@@ -130,8 +130,8 @@ trait HookUtils
130
  public function removeHook($hook, $function, $priority = 10)
131
  {
132
  $hook = (string) $hook;
133
- if (stripos($hook, 'zencache') === 0) {
134
- $hook = GLOBAL_NS.substr($hook, strlen('zencache'));
135
  }
136
  $priority = (integer) $priority;
137
  $hook_id = $this->hookId($function);
@@ -246,8 +246,8 @@ trait HookUtils
246
  $args = func_get_args();
247
  call_user_func_array('do_action', $args);
248
 
249
- if (stripos($hook, GLOBAL_NS) === 0) {
250
- $zencache_filter = 'zencache'.substr($hook, strlen(GLOBAL_NS));
251
  $zencache_args = $args; // Use a copy of the args.
252
  $zencache_args[0] = $zencache_filter;
253
  call_user_func_array('do_action', $zencache_args);
@@ -269,8 +269,8 @@ trait HookUtils
269
  $args = func_get_args();
270
  $value = call_user_func_array('apply_filters', $args);
271
 
272
- if (stripos($hook, GLOBAL_NS) === 0) {
273
- $zencache_hook = 'zencache'.substr($hook, strlen(GLOBAL_NS));
274
  $zencache_args = $args; // Use a copy of the args.
275
  $zencache_args[0] = $zencache_hook;
276
  $zencache_args[1] = $value; // Filtered value.
60
  public function addHook($hook, $function, $priority = 10, $accepted_args = 1)
61
  {
62
  $hook = (string) $hook;
63
+ if (mb_stripos($hook, 'zencache') === 0) {
64
+ $hook = GLOBAL_NS.mb_substr($hook, mb_strlen('zencache'));
65
  }
66
  $priority = (integer) $priority;
67
  $accepted_args = max(0, (integer) $accepted_args);
130
  public function removeHook($hook, $function, $priority = 10)
131
  {
132
  $hook = (string) $hook;
133
+ if (mb_stripos($hook, 'zencache') === 0) {
134
+ $hook = GLOBAL_NS.mb_substr($hook, mb_strlen('zencache'));
135
  }
136
  $priority = (integer) $priority;
137
  $hook_id = $this->hookId($function);
246
  $args = func_get_args();
247
  call_user_func_array('do_action', $args);
248
 
249
+ if (mb_stripos($hook, GLOBAL_NS) === 0) {
250
+ $zencache_filter = 'zencache'.mb_substr($hook, mb_strlen(GLOBAL_NS));
251
  $zencache_args = $args; // Use a copy of the args.
252
  $zencache_args[0] = $zencache_filter;
253
  call_user_func_array('do_action', $zencache_args);
269
  $args = func_get_args();
270
  $value = call_user_func_array('apply_filters', $args);
271
 
272
+ if (mb_stripos($hook, GLOBAL_NS) === 0) {
273
+ $zencache_hook = 'zencache'.mb_substr($hook, mb_strlen(GLOBAL_NS));
274
  $zencache_args = $args; // Use a copy of the args.
275
  $zencache_args[0] = $zencache_hook;
276
  $zencache_args[1] = $value; // Filtered value.
src/includes/traits/Shared/HttpUtils.php CHANGED
@@ -18,9 +18,9 @@ trait HttpUtils
18
  return $protocol; // Already cached this.
19
  }
20
  if (!empty($_SERVER['SERVER_PROTOCOL']) && is_string($_SERVER['SERVER_PROTOCOL'])) {
21
- $protocol = strtoupper($_SERVER['SERVER_PROTOCOL']);
22
  }
23
- if (!$protocol || stripos($protocol, 'HTTP/') !== 0) {
24
  $protocol = 'HTTP/1.0'; // Default value.
25
  }
26
  return $protocol;
@@ -110,10 +110,10 @@ trait HttpUtils
110
  'X-Powered-By',
111
  'X-UA-Compatible',
112
  ];
113
- $cacheable_headers = array_map('strtolower', $cacheable_headers);
114
 
115
  foreach ($headers as $_key => $_header) {
116
- $_header = strtolower((string) strstr($_header, ':', true));
117
  if (!$_header || !in_array($_header, $cacheable_headers, true)) {
118
  unset($headers[$_key]);
119
  }
18
  return $protocol; // Already cached this.
19
  }
20
  if (!empty($_SERVER['SERVER_PROTOCOL']) && is_string($_SERVER['SERVER_PROTOCOL'])) {
21
+ $protocol = mb_strtoupper($_SERVER['SERVER_PROTOCOL']);
22
  }
23
+ if (!$protocol || mb_stripos($protocol, 'HTTP/') !== 0) {
24
  $protocol = 'HTTP/1.0'; // Default value.
25
  }
26
  return $protocol;
110
  'X-Powered-By',
111
  'X-UA-Compatible',
112
  ];
113
+ $cacheable_headers = array_map('mb_strtolower', $cacheable_headers);
114
 
115
  foreach ($headers as $_key => $_header) {
116
+ $_header = mb_strtolower((string) strstr($_header, ':', true));
117
  if (!$_header || !in_array($_header, $cacheable_headers, true)) {
118
  unset($headers[$_key]);
119
  }
src/includes/traits/Shared/IpAddrUtils.php CHANGED
@@ -53,7 +53,7 @@ trait IpAddrUtils
53
  unset($_key, $_source, $_valid_public_ip); // Housekeeping.
54
  }
55
  if (!empty($_SERVER['REMOTE_ADDR'])) {
56
- return $ip = strtolower((string) $_SERVER['REMOTE_ADDR']);
57
  }
58
  return $ip = 'unknown'; // Not possible.
59
  }
@@ -79,7 +79,7 @@ trait IpAddrUtils
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(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
  }
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
  }
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
  }
src/includes/traits/Shared/PatternUtils.php CHANGED
@@ -38,10 +38,10 @@ trait PatternUtils
38
  {
39
  return preg_replace(
40
  [
41
- '/\\\\\^/',
42
- '/\\\\\*\\\\\*/',
43
- '/\\\\\*/',
44
- '/\\\\\$/',
45
  ],
46
  [
47
  '^', // Beginning of line.
38
  {
39
  return preg_replace(
40
  [
41
+ '/\\\\\^/u',
42
+ '/\\\\\*\\\\\*/u',
43
+ '/\\\\\*/u',
44
+ '/\\\\\$/u',
45
  ],
46
  [
47
  '^', // Beginning of line.
src/includes/traits/Shared/ReplaceUtils.php CHANGED
@@ -8,6 +8,9 @@ trait ReplaceUtils
8
  /**
9
  * String replace ONE time.
10
  *
 
 
 
11
  * @since 150422 Rewrite.
12
  *
13
  * @param string $needle A string to search/replace.
@@ -23,17 +26,20 @@ trait ReplaceUtils
23
  $needle = (string) $needle;
24
  $replace = (string) $replace;
25
  $haystack = (string) $haystack;
26
- $caSe_strpos = $caSe_insensitive ? 'stripos' : 'strpos';
27
 
28
- if (($needle_strpos = $caSe_strpos($haystack, $needle)) === false) {
29
  return $haystack; // Nothing to replace.
30
  }
31
- return (string) substr_replace($haystack, $replace, $needle_strpos, strlen($needle));
32
  }
33
 
34
  /**
35
  * String replace ONE time (caSe-insensitive).
36
  *
 
 
 
37
  * @since 150422 Rewrite.
38
  *
39
  * @param string $needle A string to search/replace.
8
  /**
9
  * String replace ONE time.
10
  *
11
+ * @deprecated Deprecated since v160706
12
+ * @deprecated Replaced with Multibyte String support; see https://github.com/websharks/comet-cache/issues/703
13
+ *
14
  * @since 150422 Rewrite.
15
  *
16
  * @param string $needle A string to search/replace.
26
  $needle = (string) $needle;
27
  $replace = (string) $replace;
28
  $haystack = (string) $haystack;
29
+ $caSe_mb_strpos = $caSe_insensitive ? 'mb_stripos' : 'mb_strpos';
30
 
31
+ if (($needle_strpos = $caSe_mb_strpos($haystack, $needle)) === false) {
32
  return $haystack; // Nothing to replace.
33
  }
34
+ return (string) substr_replace($haystack, $replace, $needle_strpos, mb_strlen($needle));
35
  }
36
 
37
  /**
38
  * String replace ONE time (caSe-insensitive).
39
  *
40
+ * @deprecated Deprecated since v160706
41
+ * @deprecated Replaced with Multibyte String support; see https://github.com/websharks/comet-cache/issues/703
42
+ *
43
  * @since 150422 Rewrite.
44
  *
45
  * @param string $needle A string to search/replace.
src/includes/traits/Shared/ServerUtils.php CHANGED
@@ -18,10 +18,10 @@ trait ServerUtils
18
  return $is; // Already cached this.
19
  }
20
  if (!empty($_SERVER['SERVER_SOFTWARE']) && is_string($_SERVER['SERVER_SOFTWARE'])) {
21
- if (stripos($_SERVER['SERVER_SOFTWARE'], 'apache') !== false) {
22
  return $is = true;
23
  }
24
- if (stripos($_SERVER['SERVER_SOFTWARE'], 'litespeed') !== false) {
25
  return $is = true;
26
  }
27
  }
@@ -41,7 +41,7 @@ trait ServerUtils
41
  return $is; // Already cached this.
42
  }
43
  if (!empty($_SERVER['SERVER_SOFTWARE']) && is_string($_SERVER['SERVER_SOFTWARE'])) {
44
- if (stripos($_SERVER['SERVER_SOFTWARE'], 'nginx') !== false) {
45
  return $is = true;
46
  }
47
  }
@@ -61,10 +61,10 @@ trait ServerUtils
61
  return $is; // Already cached this.
62
  }
63
  if (!empty($_SERVER['SERVER_SOFTWARE']) && is_string($_SERVER['SERVER_SOFTWARE'])) {
64
- if (stripos($_SERVER['SERVER_SOFTWARE'], 'microsoft-iis') !== false) {
65
  return $is = true;
66
  }
67
- if (stripos($_SERVER['SERVER_SOFTWARE'], 'expressiondevserver') !== false) {
68
  return $is = true;
69
  }
70
  }
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
  }
24
+ if (mb_stripos($_SERVER['SERVER_SOFTWARE'], 'litespeed') !== false) {
25
  return $is = true;
26
  }
27
  }
41
  return $is; // Already cached this.
42
  }
43
  if (!empty($_SERVER['SERVER_SOFTWARE']) && is_string($_SERVER['SERVER_SOFTWARE'])) {
44
+ if (mb_stripos($_SERVER['SERVER_SOFTWARE'], 'nginx') !== false) {
45
  return $is = true;
46
  }
47
  }
61
  return $is; // Already cached this.
62
  }
63
  if (!empty($_SERVER['SERVER_SOFTWARE']) && is_string($_SERVER['SERVER_SOFTWARE'])) {
64
+ if (mb_stripos($_SERVER['SERVER_SOFTWARE'], 'microsoft-iis') !== false) {
65
  return $is = true;
66
  }
67
+ if (mb_stripos($_SERVER['SERVER_SOFTWARE'], 'expressiondevserver') !== false) {
68
  return $is = true;
69
  }
70
  }
src/includes/traits/Shared/StringUtils.php CHANGED
@@ -32,13 +32,13 @@ trait StringUtils
32
  $max_length = max(4, $max_length);
33
 
34
  $string = strip_tags($string);
35
- $string = preg_replace('/\s+/', ' ', strip_tags($string));
36
  $string = trim($string); // Trim it up now.
37
 
38
- if (strlen($string) > $max_length) {
39
- $string = (string) substr($string, 0, $max_length - 3).'...';
40
- } elseif ($force_ellipsis && strlen($string) + 3 > $max_length) {
41
- $string = (string) substr($string, 0, $max_length - 3).'...';
42
  } else {
43
  $string .= $force_ellipsis ? '...' : '';
44
  }
@@ -71,10 +71,10 @@ trait StringUtils
71
  $max_length = max(4, $max_length);
72
 
73
  $string = strip_tags($string);
74
- $string = preg_replace('/\s+/', ' ', strip_tags($string));
75
  $string = trim($string); // Trim it up now.
76
 
77
- if (strlen($string) <= $max_length) {
78
  return $string; // Nothing to do.
79
  }
80
  $full_string = $string;
@@ -82,12 +82,12 @@ trait StringUtils
82
 
83
  $first_clip = $half_max_length - 3;
84
  $string = $first_clip >= 1 // Something?
85
- ? substr($full_string, 0, $first_clip).'...'
86
  : '...'; // Ellipsis only.
87
 
88
- $second_clip = strlen($full_string) - ($max_length - strlen($string));
89
  $string .= $second_clip >= 0 && $second_clip >= $first_clip
90
- ? substr($full_string, $second_clip) : '';
91
 
92
  return $string;
93
  }
32
  $max_length = max(4, $max_length);
33
 
34
  $string = strip_tags($string);
35
+ $string = preg_replace('/\s+/u', ' ', strip_tags($string));
36
  $string = trim($string); // Trim it up now.
37
 
38
+ if (mb_strlen($string) > $max_length) {
39
+ $string = (string) mb_substr($string, 0, $max_length - 3).'...';
40
+ } elseif ($force_ellipsis && mb_strlen($string) + 3 > $max_length) {
41
+ $string = (string) mb_substr($string, 0, $max_length - 3).'...';
42
  } else {
43
  $string .= $force_ellipsis ? '...' : '';
44
  }
71
  $max_length = max(4, $max_length);
72
 
73
  $string = strip_tags($string);
74
+ $string = preg_replace('/\s+/u', ' ', strip_tags($string));
75
  $string = trim($string); // Trim it up now.
76
 
77
+ if (mb_strlen($string) <= $max_length) {
78
  return $string; // Nothing to do.
79
  }
80
  $full_string = $string;
82
 
83
  $first_clip = $half_max_length - 3;
84
  $string = $first_clip >= 1 // Something?
85
+ ? mb_substr($full_string, 0, $first_clip).'...'
86
  : '...'; // Ellipsis only.
87
 
88
+ $second_clip = mb_strlen($full_string) - ($max_length - mb_strlen($string));
89
  $string .= $second_clip >= 0 && $second_clip >= $first_clip
90
+ ? mb_substr($full_string, $second_clip) : '';
91
 
92
  return $string;
93
  }
src/includes/traits/Shared/TokenUtils.php CHANGED
@@ -29,24 +29,27 @@ trait TokenUtils
29
  $token = ''; // Initialize token value.
30
 
31
  if (!is_multisite() || $this->isAdvancedCache()) {
32
- $token = (string) $_SERVER['HTTP_HOST'];
33
  } elseif ($consider_domain_mapping && $this->canConsiderDomainMapping()) {
34
  if (($consider_domain_mapping_domain = trim((string) $consider_domain_mapping_domain))) {
35
  $token = $consider_domain_mapping_domain;
36
  } elseif ($this->isDomainMapping()) {
37
- $token = (string) $_SERVER['HTTP_HOST'];
38
  } else { // For the current blog ID.
39
  $token = $this->domainMappingUrlFilter($this->currentUrl());
40
  $token = $this->parseUrl($token, PHP_URL_HOST);
41
  }
42
  }
43
  if (!$token) { // Use default?
44
- $token = (string) $_SERVER['HTTP_HOST'];
 
 
 
45
  }
46
  if ($token) { // Have token?
47
- $token = strtolower($token);
48
  if ($dashify) { // Dashify it?
49
- $token = preg_replace('/[^a-z0-9]/i', '-', $token);
50
  $token = trim($token, '-');
51
  }
52
  }
@@ -86,9 +89,9 @@ trait TokenUtils
86
  $token = $blog_details->domain; // Unmapped domain.
87
  }
88
  if ($token) { // Have token?
89
- $token = strtolower($token);
90
  if ($dashify) { // Dashify it?
91
- $token = preg_replace('/[^a-z0-9]/i', '-', $token);
92
  $token = trim($token, '-');
93
  }
94
  }
@@ -131,7 +134,7 @@ trait TokenUtils
131
  $token = isset($token[0]) ? '/'.$token.'/' : '/';
132
 
133
  if ($token !== '/' && $dashify) {
134
- $token = preg_replace('/[^a-z0-9\/]/i', '-', $token);
135
  $token = trim($token, '-');
136
  }
137
  return $token;
@@ -173,7 +176,7 @@ trait TokenUtils
173
  return $token; // Not applicable.
174
  }
175
  if ($path && $path !== '/' && ($host_base_token = trim($this->hostBaseToken(), '/'))) {
176
- $path_minus_base = preg_replace('/^\/'.preg_quote($host_base_token, '/').'(\/|$)/i', '${1}', $path);
177
  } else {
178
  $path_minus_base = $path; // Default value.
179
  }
@@ -182,13 +185,13 @@ trait TokenUtils
182
  $token = isset($token[0]) ? '/'.$token.'/' : '/';
183
 
184
  if ($token !== '/') { // Perhaps NOT the main site?
185
- $blog_paths_file = $this->cacheDir().'/'.strtolower(SHORT_NAME).'-blog-paths';
186
  if (!is_file($blog_paths_file) || !in_array($token, unserialize(file_get_contents($blog_paths_file)), true)) {
187
  $token = '/'; // NOT a real/valid child blog path.
188
  }
189
  }
190
  if ($token !== '/' && $dashify) {
191
- $token = preg_replace('/[^a-z0-9\/]/i', '-', $token);
192
  $token = trim($token, '-');
193
  }
194
  return $token;
@@ -224,7 +227,7 @@ trait TokenUtils
224
  if (($blog_details = $this->blogDetails($blog_id))) {
225
  $path = $blog_details->path; // e.g., `[/base]/path/` (includes base).
226
  if ($path && $path !== '/' && ($host_base_token = trim($this->hostBaseToken(), '/'))) {
227
- $path_minus_base = preg_replace('/^\/'.preg_quote($host_base_token, '/').'(\/|$)/i', '${1}', $path);
228
  } else {
229
  $path_minus_base = $path; // Default value.
230
  }
@@ -234,13 +237,13 @@ trait TokenUtils
234
  $token = isset($token[0]) ? '/'.$token.'/' : '/';
235
 
236
  if ($token !== '/') { // Perhaps NOT the main site?
237
- $blog_paths_file = $this->cacheDir().'/'.strtolower(SHORT_NAME).'-blog-paths';
238
  if (!is_file($blog_paths_file) || !in_array($token, unserialize(file_get_contents($blog_paths_file)), true)) {
239
  $token = '/'; // NOT a real/valid child blog path.
240
  }
241
  }
242
  if ($token !== '/' && $dashify) {
243
- $token = preg_replace('/[^a-z0-9\/]/i', '-', $token);
244
  $token = trim($token, '-');
245
  }
246
  return $token;
@@ -268,7 +271,7 @@ trait TokenUtils
268
  $tokens = $this->hostBaseToken($dashify, $consider_domain_mapping);
269
  $tokens .= $this->hostDirToken($dashify, $consider_domain_mapping, $path);
270
 
271
- return $tokens = preg_replace('/\/+/', '/', $tokens);
272
  }
273
 
274
  /**
@@ -290,7 +293,7 @@ trait TokenUtils
290
  $tokens = $this->hostBaseToken($dashify, $consider_domain_mapping);
291
  $tokens .= $this->hostDirTokenForBlog($dashify, $consider_domain_mapping, $blog_id);
292
 
293
- return $tokens = preg_replace('/\/+/', '/', $tokens);
294
  }
295
 
296
 
29
  $token = ''; // Initialize token value.
30
 
31
  if (!is_multisite() || $this->isAdvancedCache()) {
32
+ $token = !empty($_SERVER['HTTP_HOST']) ? (string) $_SERVER['HTTP_HOST'] : '';
33
  } elseif ($consider_domain_mapping && $this->canConsiderDomainMapping()) {
34
  if (($consider_domain_mapping_domain = trim((string) $consider_domain_mapping_domain))) {
35
  $token = $consider_domain_mapping_domain;
36
  } elseif ($this->isDomainMapping()) {
37
+ $token = !empty($_SERVER['HTTP_HOST']) ? (string) $_SERVER['HTTP_HOST'] : '';
38
  } else { // For the current blog ID.
39
  $token = $this->domainMappingUrlFilter($this->currentUrl());
40
  $token = $this->parseUrl($token, PHP_URL_HOST);
41
  }
42
  }
43
  if (!$token) { // Use default?
44
+ $token = !empty($_SERVER['HTTP_HOST']) ? (string) $_SERVER['HTTP_HOST'] : '';
45
+ }
46
+ if (!$token && $this->isPlugin()) {
47
+ $token = (string) parse_url(home_url(), PHP_URL_HOST);
48
  }
49
  if ($token) { // Have token?
50
+ $token = mb_strtolower($token);
51
  if ($dashify) { // Dashify it?
52
+ $token = preg_replace('/[^a-z0-9]/ui', '-', $token);
53
  $token = trim($token, '-');
54
  }
55
  }
89
  $token = $blog_details->domain; // Unmapped domain.
90
  }
91
  if ($token) { // Have token?
92
+ $token = mb_strtolower($token);
93
  if ($dashify) { // Dashify it?
94
+ $token = preg_replace('/[^a-z0-9]/ui', '-', $token);
95
  $token = trim($token, '-');
96
  }
97
  }
134
  $token = isset($token[0]) ? '/'.$token.'/' : '/';
135
 
136
  if ($token !== '/' && $dashify) {
137
+ $token = preg_replace('/[^a-z0-9\/]/ui', '-', $token);
138
  $token = trim($token, '-');
139
  }
140
  return $token;
176
  return $token; // Not applicable.
177
  }
178
  if ($path && $path !== '/' && ($host_base_token = trim($this->hostBaseToken(), '/'))) {
179
+ $path_minus_base = preg_replace('/^\/'.preg_quote($host_base_token, '/').'(\/|$)/ui', '${1}', $path);
180
  } else {
181
  $path_minus_base = $path; // Default value.
182
  }
185
  $token = isset($token[0]) ? '/'.$token.'/' : '/';
186
 
187
  if ($token !== '/') { // Perhaps NOT the main site?
188
+ $blog_paths_file = $this->cacheDir().'/'.mb_strtolower(SHORT_NAME).'-blog-paths';
189
  if (!is_file($blog_paths_file) || !in_array($token, unserialize(file_get_contents($blog_paths_file)), true)) {
190
  $token = '/'; // NOT a real/valid child blog path.
191
  }
192
  }
193
  if ($token !== '/' && $dashify) {
194
+ $token = preg_replace('/[^a-z0-9\/]/ui', '-', $token);
195
  $token = trim($token, '-');
196
  }
197
  return $token;
227
  if (($blog_details = $this->blogDetails($blog_id))) {
228
  $path = $blog_details->path; // e.g., `[/base]/path/` (includes base).
229
  if ($path && $path !== '/' && ($host_base_token = trim($this->hostBaseToken(), '/'))) {
230
+ $path_minus_base = preg_replace('/^\/'.preg_quote($host_base_token, '/').'(\/|$)/ui', '${1}', $path);
231
  } else {
232
  $path_minus_base = $path; // Default value.
233
  }
237
  $token = isset($token[0]) ? '/'.$token.'/' : '/';
238
 
239
  if ($token !== '/') { // Perhaps NOT the main site?
240
+ $blog_paths_file = $this->cacheDir().'/'.mb_strtolower(SHORT_NAME).'-blog-paths';
241
  if (!is_file($blog_paths_file) || !in_array($token, unserialize(file_get_contents($blog_paths_file)), true)) {
242
  $token = '/'; // NOT a real/valid child blog path.
243
  }
244
  }
245
  if ($token !== '/' && $dashify) {
246
+ $token = preg_replace('/[^a-z0-9\/]/ui', '-', $token);
247
  $token = trim($token, '-');
248
  }
249
  return $token;
271
  $tokens = $this->hostBaseToken($dashify, $consider_domain_mapping);
272
  $tokens .= $this->hostDirToken($dashify, $consider_domain_mapping, $path);
273
 
274
+ return $tokens = preg_replace('/\/+/u', '/', $tokens);
275
  }
276
 
277
  /**
293
  $tokens = $this->hostBaseToken($dashify, $consider_domain_mapping);
294
  $tokens .= $this->hostDirTokenForBlog($dashify, $consider_domain_mapping, $blog_id);
295
 
296
+ return $tokens = preg_replace('/\/+/u', '/', $tokens);
297
  }
298
 
299
 
src/includes/traits/Shared/UrlUtils.php CHANGED
@@ -19,9 +19,9 @@ trait UrlUtils
19
  {
20
  $url_uri_qsl = (string) $url_uri_qsl;
21
  $component = (integer) $component;
22
- ${'//'} = strpos($url_uri_qsl, '//') === 0;
23
 
24
- if ($url_uri_qsl && strpos($url_uri_qsl, '&amp;') !== false) {
25
  $url_uri_qsl = str_replace('&amp;', '&', $url_uri_qsl);
26
  }
27
  if ($component > -1) {
@@ -135,6 +135,9 @@ trait UrlUtils
135
  */
136
  public function currentUrl()
137
  {
 
 
 
138
  return ($this->isSsl() ? 'https://' : 'http://').$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'];
139
  }
140
  }
19
  {
20
  $url_uri_qsl = (string) $url_uri_qsl;
21
  $component = (integer) $component;
22
+ ${'//'} = mb_strpos($url_uri_qsl, '//') === 0;
23
 
24
+ if ($url_uri_qsl && mb_strpos($url_uri_qsl, '&amp;') !== false) {
25
  $url_uri_qsl = str_replace('&amp;', '&', $url_uri_qsl);
26
  }
27
  if ($component > -1) {
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
  }
src/vendor/autoload.php CHANGED
@@ -4,4 +4,4 @@
4
 
5
  require_once __DIR__ . '/composer' . '/autoload_real.php';
6
 
7
- return ComposerAutoloaderInit42cd68716e26c15cd28e74de3dd5e314::getLoader();
4
 
5
  require_once __DIR__ . '/composer' . '/autoload_real.php';
6
 
7
+ return ComposerAutoloaderInit0ecf493fec48f48e608cdb485c29bf1b::getLoader();
src/vendor/composer/autoload_classmap.php CHANGED
@@ -6,4 +6,81 @@ $vendorDir = dirname(dirname(__FILE__));
6
  $baseDir = dirname(dirname($vendorDir));
7
 
8
  return array(
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
  );
6
  $baseDir = dirname(dirname($vendorDir));
7
 
8
  return array(
9
+ 'WebSharks\\CometCache\\Classes\\AbsBase' => $baseDir . '/src/includes/classes/AbsBase.php',
10
+ 'WebSharks\\CometCache\\Classes\\AbsBaseAp' => $baseDir . '/src/includes/classes/AbsBaseAp.php',
11
+ 'WebSharks\\CometCache\\Classes\\Actions' => $baseDir . '/src/includes/classes/Actions.php',
12
+ 'WebSharks\\CometCache\\Classes\\AdvCacheBackCompat' => $baseDir . '/src/includes/classes/AdvCacheBackCompat.php',
13
+ 'WebSharks\\CometCache\\Classes\\AdvancedCache' => $baseDir . '/src/includes/classes/AdvancedCache.php',
14
+ 'WebSharks\\CometCache\\Classes\\ApiBase' => $baseDir . '/src/includes/classes/ApiBase.php',
15
+ 'WebSharks\\CometCache\\Classes\\Conflicts' => $baseDir . '/src/includes/classes/Conflicts.php',
16
+ 'WebSharks\\CometCache\\Classes\\FeedUtils' => $baseDir . '/src/includes/classes/FeedUtils.php',
17
+ 'WebSharks\\CometCache\\Classes\\MenuPage' => $baseDir . '/src/includes/classes/MenuPage.php',
18
+ 'WebSharks\\CometCache\\Classes\\MenuPageOptions' => $baseDir . '/src/includes/classes/MenuPageOptions.php',
19
+ 'WebSharks\\CometCache\\Classes\\Plugin' => $baseDir . '/src/includes/classes/Plugin.php',
20
+ 'WebSharks\\CometCache\\Classes\\VsUpgrades' => $baseDir . '/src/includes/classes/VsUpgrades.php',
21
+ 'WebSharks\\CometCache\\Interfaces\\Shared\\CachePathConsts' => $baseDir . '/src/includes/interfaces/Shared/CachePathConsts.php',
22
+ 'WebSharks\\CometCache\\Interfaces\\Shared\\NcDebugConsts' => $baseDir . '/src/includes/interfaces/Shared/NcDebugConsts.php',
23
+ 'WebSharks\\CometCache\\Traits\\Ac\\AbortUtils' => $baseDir . '/src/includes/traits/Ac/AbortUtils.php',
24
+ 'WebSharks\\CometCache\\Traits\\Ac\\AcPluginUtils' => $baseDir . '/src/includes/traits/Ac/AcPluginUtils.php',
25
+ 'WebSharks\\CometCache\\Traits\\Ac\\ClientSideUtils' => $baseDir . '/src/includes/traits/Ac/ClientSideUtils.php',
26
+ 'WebSharks\\CometCache\\Traits\\Ac\\NcDebugUtils' => $baseDir . '/src/includes/traits/Ac/NcDebugUtils.php',
27
+ 'WebSharks\\CometCache\\Traits\\Ac\\ObUtils' => $baseDir . '/src/includes/traits/Ac/ObUtils.php',
28
+ 'WebSharks\\CometCache\\Traits\\Ac\\PostloadUtils' => $baseDir . '/src/includes/traits/Ac/PostloadUtils.php',
29
+ 'WebSharks\\CometCache\\Traits\\Ac\\ShutdownUtils' => $baseDir . '/src/includes/traits/Ac/ShutdownUtils.php',
30
+ 'WebSharks\\CometCache\\Traits\\Plugin\\ActionUtils' => $baseDir . '/src/includes/traits/Plugin/ActionUtils.php',
31
+ 'WebSharks\\CometCache\\Traits\\Plugin\\BbPressUtils' => $baseDir . '/src/includes/traits/Plugin/BbPressUtils.php',
32
+ 'WebSharks\\CometCache\\Traits\\Plugin\\CleanupUtils' => $baseDir . '/src/includes/traits/Plugin/CleanupUtils.php',
33
+ 'WebSharks\\CometCache\\Traits\\Plugin\\CondUtils' => $baseDir . '/src/includes/traits/Plugin/CondUtils.php',
34
+ 'WebSharks\\CometCache\\Traits\\Plugin\\CronUtils' => $baseDir . '/src/includes/traits/Plugin/CronUtils.php',
35
+ 'WebSharks\\CometCache\\Traits\\Plugin\\DbUtils' => $baseDir . '/src/includes/traits/Plugin/DbUtils.php',
36
+ 'WebSharks\\CometCache\\Traits\\Plugin\\DirUtils' => $baseDir . '/src/includes/traits/Plugin/DirUtils.php',
37
+ 'WebSharks\\CometCache\\Traits\\Plugin\\HtaccessUtils' => $baseDir . '/src/includes/traits/Plugin/HtaccessUtils.php',
38
+ 'WebSharks\\CometCache\\Traits\\Plugin\\InstallUtils' => $baseDir . '/src/includes/traits/Plugin/InstallUtils.php',
39
+ 'WebSharks\\CometCache\\Traits\\Plugin\\MenuPageUtils' => $baseDir . '/src/includes/traits/Plugin/MenuPageUtils.php',
40
+ 'WebSharks\\CometCache\\Traits\\Plugin\\NoticeUtils' => $baseDir . '/src/includes/traits/Plugin/NoticeUtils.php',
41
+ 'WebSharks\\CometCache\\Traits\\Plugin\\OptionUtils' => $baseDir . '/src/includes/traits/Plugin/OptionUtils.php',
42
+ 'WebSharks\\CometCache\\Traits\\Plugin\\PostUtils' => $baseDir . '/src/includes/traits/Plugin/PostUtils.php',
43
+ 'WebSharks\\CometCache\\Traits\\Plugin\\UpdateUtils' => $baseDir . '/src/includes/traits/Plugin/UpdateUtils.php',
44
+ 'WebSharks\\CometCache\\Traits\\Plugin\\UrlUtils' => $baseDir . '/src/includes/traits/Plugin/UrlUtils.php',
45
+ 'WebSharks\\CometCache\\Traits\\Plugin\\UserUtils' => $baseDir . '/src/includes/traits/Plugin/UserUtils.php',
46
+ 'WebSharks\\CometCache\\Traits\\Plugin\\WcpAuthorUtils' => $baseDir . '/src/includes/traits/Plugin/WcpAuthorUtils.php',
47
+ 'WebSharks\\CometCache\\Traits\\Plugin\\WcpCommentUtils' => $baseDir . '/src/includes/traits/Plugin/WcpCommentUtils.php',
48
+ 'WebSharks\\CometCache\\Traits\\Plugin\\WcpFeedUtils' => $baseDir . '/src/includes/traits/Plugin/WcpFeedUtils.php',
49
+ 'WebSharks\\CometCache\\Traits\\Plugin\\WcpHomeBlogUtils' => $baseDir . '/src/includes/traits/Plugin/WcpHomeBlogUtils.php',
50
+ 'WebSharks\\CometCache\\Traits\\Plugin\\WcpJetpackUtils' => $baseDir . '/src/includes/traits/Plugin/WcpJetpackUtils.php',
51
+ 'WebSharks\\CometCache\\Traits\\Plugin\\WcpOpcacheUtils' => $baseDir . '/src/includes/traits/Plugin/WcpOpcacheUtils.php',
52
+ 'WebSharks\\CometCache\\Traits\\Plugin\\WcpPluginUtils' => $baseDir . '/src/includes/traits/Plugin/WcpPluginUtils.php',
53
+ 'WebSharks\\CometCache\\Traits\\Plugin\\WcpPostTypeUtils' => $baseDir . '/src/includes/traits/Plugin/WcpPostTypeUtils.php',
54
+ 'WebSharks\\CometCache\\Traits\\Plugin\\WcpPostUtils' => $baseDir . '/src/includes/traits/Plugin/WcpPostUtils.php',
55
+ 'WebSharks\\CometCache\\Traits\\Plugin\\WcpSettingUtils' => $baseDir . '/src/includes/traits/Plugin/WcpSettingUtils.php',
56
+ 'WebSharks\\CometCache\\Traits\\Plugin\\WcpSitemapUtils' => $baseDir . '/src/includes/traits/Plugin/WcpSitemapUtils.php',
57
+ 'WebSharks\\CometCache\\Traits\\Plugin\\WcpTermUtils' => $baseDir . '/src/includes/traits/Plugin/WcpTermUtils.php',
58
+ 'WebSharks\\CometCache\\Traits\\Plugin\\WcpUpdaterUtils' => $baseDir . '/src/includes/traits/Plugin/WcpUpdaterUtils.php',
59
+ 'WebSharks\\CometCache\\Traits\\Plugin\\WcpUtils' => $baseDir . '/src/includes/traits/Plugin/WcpUtils.php',
60
+ 'WebSharks\\CometCache\\Traits\\Plugin\\WcpWooCommerceUtils' => $baseDir . '/src/includes/traits/Plugin/WcpWooCommerceUtils.php',
61
+ 'WebSharks\\CometCache\\Traits\\Shared\\BlogUtils' => $baseDir . '/src/includes/traits/Shared/BlogUtils.php',
62
+ 'WebSharks\\CometCache\\Traits\\Shared\\CacheDirUtils' => $baseDir . '/src/includes/traits/Shared/CacheDirUtils.php',
63
+ 'WebSharks\\CometCache\\Traits\\Shared\\CacheLockUtils' => $baseDir . '/src/includes/traits/Shared/CacheLockUtils.php',
64
+ 'WebSharks\\CometCache\\Traits\\Shared\\CachePathUtils' => $baseDir . '/src/includes/traits/Shared/CachePathUtils.php',
65
+ 'WebSharks\\CometCache\\Traits\\Shared\\ConditionalUtils' => $baseDir . '/src/includes/traits/Shared/ConditionalUtils.php',
66
+ 'WebSharks\\CometCache\\Traits\\Shared\\DomainMappingUtils' => $baseDir . '/src/includes/traits/Shared/DomainMappingUtils.php',
67
+ 'WebSharks\\CometCache\\Traits\\Shared\\EscapeUtils' => $baseDir . '/src/includes/traits/Shared/EscapeUtils.php',
68
+ 'WebSharks\\CometCache\\Traits\\Shared\\FsUtils' => $baseDir . '/src/includes/traits/Shared/FsUtils.php',
69
+ 'WebSharks\\CometCache\\Traits\\Shared\\HookUtils' => $baseDir . '/src/includes/traits/Shared/HookUtils.php',
70
+ 'WebSharks\\CometCache\\Traits\\Shared\\HttpUtils' => $baseDir . '/src/includes/traits/Shared/HttpUtils.php',
71
+ 'WebSharks\\CometCache\\Traits\\Shared\\I18nUtils' => $baseDir . '/src/includes/traits/Shared/I18nUtils.php',
72
+ 'WebSharks\\CometCache\\Traits\\Shared\\IpAddrUtils' => $baseDir . '/src/includes/traits/Shared/IpAddrUtils.php',
73
+ 'WebSharks\\CometCache\\Traits\\Shared\\PatternUtils' => $baseDir . '/src/includes/traits/Shared/PatternUtils.php',
74
+ 'WebSharks\\CometCache\\Traits\\Shared\\ReplaceUtils' => $baseDir . '/src/includes/traits/Shared/ReplaceUtils.php',
75
+ 'WebSharks\\CometCache\\Traits\\Shared\\ServerUtils' => $baseDir . '/src/includes/traits/Shared/ServerUtils.php',
76
+ 'WebSharks\\CometCache\\Traits\\Shared\\StringUtils' => $baseDir . '/src/includes/traits/Shared/StringUtils.php',
77
+ 'WebSharks\\CometCache\\Traits\\Shared\\SysUtils' => $baseDir . '/src/includes/traits/Shared/SysUtils.php',
78
+ 'WebSharks\\CometCache\\Traits\\Shared\\TokenUtils' => $baseDir . '/src/includes/traits/Shared/TokenUtils.php',
79
+ 'WebSharks\\CometCache\\Traits\\Shared\\TrimUtils' => $baseDir . '/src/includes/traits/Shared/TrimUtils.php',
80
+ 'WebSharks\\CometCache\\Traits\\Shared\\UrlUtils' => $baseDir . '/src/includes/traits/Shared/UrlUtils.php',
81
+ 'WebSharks\\CssMinifier\\Core' => $vendorDir . '/websharks/css-minifier/src/includes/classes/Core.php',
82
+ 'WebSharks\\HtmlCompressor\\Benchmark' => $vendorDir . '/websharks/html-compressor/src/includes/classes/Benchmark.php',
83
+ 'WebSharks\\HtmlCompressor\\Core' => $vendorDir . '/websharks/html-compressor/src/includes/classes/Core.php',
84
+ 'WebSharks\\HtmlCompressor\\HookApi' => $vendorDir . '/websharks/html-compressor/src/includes/classes/HookApi.php',
85
+ 'WebSharks\\JsMinifier\\Core' => $vendorDir . '/websharks/js-minifier/src/includes/classes/Core.php',
86
  );
src/vendor/composer/autoload_real.php CHANGED
@@ -2,7 +2,7 @@
2
 
3
  // autoload_real.php @generated by Composer
4
 
5
- class ComposerAutoloaderInit42cd68716e26c15cd28e74de3dd5e314
6
  {
7
  private static $loader;
8
 
@@ -19,9 +19,9 @@ class ComposerAutoloaderInit42cd68716e26c15cd28e74de3dd5e314
19
  return self::$loader;
20
  }
21
 
22
- spl_autoload_register(array('ComposerAutoloaderInit42cd68716e26c15cd28e74de3dd5e314', 'loadClassLoader'), true, true);
23
  self::$loader = $loader = new \Composer\Autoload\ClassLoader();
24
- spl_autoload_unregister(array('ComposerAutoloaderInit42cd68716e26c15cd28e74de3dd5e314', 'loadClassLoader'));
25
 
26
  $map = require __DIR__ . '/autoload_namespaces.php';
27
  foreach ($map as $namespace => $path) {
2
 
3
  // autoload_real.php @generated by Composer
4
 
5
+ class ComposerAutoloaderInit0ecf493fec48f48e608cdb485c29bf1b
6
  {
7
  private static $loader;
8
 
19
  return self::$loader;
20
  }
21
 
22
+ spl_autoload_register(array('ComposerAutoloaderInit0ecf493fec48f48e608cdb485c29bf1b', 'loadClassLoader'), true, true);
23
  self::$loader = $loader = new \Composer\Autoload\ClassLoader();
24
+ spl_autoload_unregister(array('ComposerAutoloaderInit0ecf493fec48f48e608cdb485c29bf1b', 'loadClassLoader'));
25
 
26
  $map = require __DIR__ . '/autoload_namespaces.php';
27
  foreach ($map as $namespace => $path) {
src/vendor/composer/installed.json CHANGED
@@ -274,67 +274,5 @@
274
  "websharks",
275
  "wordpress"
276
  ]
277
- },
278
- {
279
- "name": "package/bourbon",
280
- "version": "4.2.3",
281
- "version_normalized": "4.2.3.0",
282
- "dist": {
283
- "type": "zip",
284
- "url": "https://github.com/thoughtbot/bourbon/releases/download/v4.2.3/bourbon-v4.2.3.zip",
285
- "reference": null,
286
- "shasum": null
287
- },
288
- "type": "library",
289
- "installation-source": "dist"
290
- },
291
- {
292
- "name": "websharks/wp-i18n-tools",
293
- "version": "dev-master",
294
- "version_normalized": "9999999-dev",
295
- "source": {
296
- "type": "git",
297
- "url": "https://github.com/websharks/wp-i18n-tools.git",
298
- "reference": "0275dc189293aee71e80a8bde43c4087f81ce9bb"
299
- },
300
- "dist": {
301
- "type": "zip",
302
- "url": "https://api.github.com/repos/websharks/wp-i18n-tools/zipball/0275dc189293aee71e80a8bde43c4087f81ce9bb",
303
- "reference": "0275dc189293aee71e80a8bde43c4087f81ce9bb",
304
- "shasum": ""
305
- },
306
- "time": "2016-04-16 08:29:33",
307
- "type": "library",
308
- "installation-source": "dist",
309
- "notification-url": "https://packagist.org/downloads/",
310
- "license": [
311
- "GPL-3.0+"
312
- ],
313
- "authors": [
314
- {
315
- "name": "websharks",
316
- "homepage": "http://websharks-inc.com/",
317
- "role": "company"
318
- },
319
- {
320
- "name": "jaswsinc",
321
- "homepage": "http://jaswsinc.com/",
322
- "role": "developer"
323
- },
324
- {
325
- "name": "raamdev",
326
- "homepage": "http://raam.org/",
327
- "role": "developer"
328
- }
329
- ],
330
- "description": "WordPress i18n/translation tools.",
331
- "homepage": "https://github.com/websharks/wp-i18n-tools",
332
- "keywords": [
333
- "gettext",
334
- "i18n",
335
- "translation",
336
- "websharks",
337
- "wordpress"
338
- ]
339
  }
340
  ]
274
  "websharks",
275
  "wordpress"
276
  ]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
277
  }
278
  ]