Comet Cache - Version 161119

Version Description

= v160416 =

Requires WordPress v4.2+.

Download this release

Release Info

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

Code changes from version 160917 to 161119

Files changed (34) hide show
  1. CHANGELOG.md +20 -1
  2. comet-cache.php +1 -1
  3. readme.txt +22 -21
  4. src/client-s/css/menu-pages.min.css +1 -1
  5. src/includes/classes/AbsBase.php +7 -7
  6. src/includes/classes/AbsBaseAp.php +1 -0
  7. src/includes/classes/MenuPageOptions.php +69 -75
  8. src/includes/classes/Notes.php +127 -0
  9. src/includes/classes/Plugin.php +12 -15
  10. src/includes/classes/VsUpgrades.php +25 -2
  11. src/includes/stub.php +1 -1
  12. src/includes/templates/advanced-cache.x-php +33 -23
  13. src/includes/templates/htaccess/canonical-urls-no-ts-enable.txt +1 -1
  14. src/includes/templates/htaccess/canonical-urls-ts-enable.txt +1 -1
  15. src/includes/traits/Ac/ClientSideUtils.php +13 -16
  16. src/includes/traits/Ac/NcDebugUtils.php +3 -3
  17. src/includes/traits/Ac/ObUtils.php +91 -42
  18. src/includes/traits/Ac/PostloadUtils.php +9 -9
  19. src/includes/traits/Plugin/AdminBarUtils.php +9 -9
  20. src/includes/traits/Plugin/InstallUtils.php +10 -1
  21. src/includes/traits/Plugin/MenuPageUtils.php +6 -3
  22. src/includes/traits/Plugin/NoticeUtils.php +18 -17
  23. src/includes/traits/Plugin/OptionUtils.php +9 -6
  24. src/includes/traits/Plugin/WcpWooCommerceUtils.php +23 -0
  25. src/includes/traits/Shared/ArrayUtils.php +33 -0
  26. src/includes/traits/Shared/CachePathUtils.php +46 -10
  27. src/includes/traits/Shared/ConditionalUtils.php +86 -113
  28. src/includes/traits/Shared/StringUtils.php +54 -0
  29. src/vendor/autoload.php +1 -1
  30. src/vendor/composer/autoload_classmap.php +2 -0
  31. src/vendor/composer/autoload_real.php +3 -3
  32. src/vendor/composer/installed.json +6 -6
  33. src/vendor/websharks/sharkicons/README.md +154 -0
  34. src/vendor/websharks/wp-php-rv/README.md +124 -0
CHANGELOG.md CHANGED
@@ -1,6 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  = v160917 =
2
 
3
- - **New Feature** (Lite): The Clear Cache button is now available in the Admin Toolbar for the Lite version of Comet Cache.
4
  - **New Feature** (Pro): Comet Cache Pro is now fully compatible with [WordPress Automatic Background Updates](https://codex.wordpress.org/Configuring_Automatic_Background_Updates#Plugin_.26_Theme_Updates_via_Filter). If you enable automatic background updates for plugins, and you save valid Comet Cache Pro License Credentials in the _Comet Cache Pro → Plugin Options → Update Credentials_ panel, you will automatically receive Pro plugin updates. Props @jaswsinc. See [Issue #289](https://github.com/websharks/comet-cache/issues/289).
5
  - **Bug Fix**: In some scenarios Comet Cache might produce a false-positive "Warning: mkdir(): File exists" message when checking if the cache directory exists. Comet Cache now calls `clearstatcache()` and uses `file_exists()` instead of `is_dir()` to help make this check more robust. See [Issue #786](https://github.com/websharks/comet-cache/issues/786).
6
  - **Bug Fix**: Fixed a bug where the Comet Cache PHP requirements check would fail and produce a fatal error when upgrading from a version of Comet Cache that did not require an extension that is now required by newer releases. This would occur when, for example, the required PHP `mbstring` extension was missing. Props @jaswsinc for finding the bug. See [Issue #817](https://github.com/websharks/comet-cache/issues/817).
1
+ = v161119 =
2
+
3
+ - **Bug Fix:** Avoid browser autocomplete in configuration fields by adding `autocomplete="off"` to all form tags in Comet Cache menu pages. See [Issue #832](https://github.com/websharks/comet-cache/issues/832).
4
+ - **Bug Fix:** Fixed a broken link to the [Static CDN Filters tutorial for MaxCDN integration](http://cometcache.com/r/static-cdn-filters-maxcdn/). Props @kristineds. See [Issue #842](https://github.com/websharks/comet-cache/issues/842).
5
+ - **Bug Fix:** Multisite installations inside a subdirectory were broken by Apache Optimizations via `.htaccess` in some scenarios. Fixed in this release. See [Issue #798](https://github.com/websharks/comet-cache/issues/798).
6
+ - **Bug Fix:** Don't enqueue `Chart.js` unnecessarily in lite version of the software. See [Issue #830](https://github.com/websharks/comet-cache/issues/830).
7
+ - **Bug Fix:** Enhancing WooCommerce integration by listening to the `woocommerce_product_set_stock_status` hook in addition to the `woocommerce_product_set_stock` hook. See [Issue #674](https://github.com/websharks/comet-cache/issues/674).
8
+ - **Bug Fix** (Pro): Automatically dismiss any persistent update notifications whenever a new version of the software is recompiled; i.e., don't continue to show an upgrade notice whenever the software has just been updated by a site owner. See [Issue #806](https://github.com/websharks/comet-cache/issues/806).
9
+ - **Enhancement:** This version enhances the HTML comments left in the source code (HTML Debug Notes). When debug notes are enabled (i.e., HTML comments) they are now broken down into key/value pairs and tabulated for a cleaner display and easier debugging. See [Issue #790](https://github.com/websharks/comet-cache/issues/790).
10
+ - **Performance Enhancement:** For sites configured to allow query string variables into the cache, those variables are now sorted by key name internally to avoid duplicate cache files; i.e., whenever the order of query string variables changes from request to another, but with the same exact values. In short, Comet Cache now knows how to serve the same underlying cache file; i.e., from a previous request that may have had the same query string, just in a slightly different order. See [Issue #639](https://github.com/websharks/comet-cache/issues/639).
11
+ - **UI Enhancement:** The Comet Cache UI is now fully Responsive with an improved UI on laptop and mobile devices. Props @renzms. See [Issue #699](https://github.com/websharks/comet-cache/issues/699).
12
+ - **UI Enhancement:** This release improves the toggle link that allows you to see additional details whenever Comet Cache automatically clears more than one facet of the cache. See [Issue #837](https://github.com/websharks/comet-cache/issues/837) and [Issue #831](https://github.com/websharks/comet-cache/issues/831).
13
+ - **UI Enhancement** (Pro): Following improvements to the update API in a previous release of Comet Cache that made it possible to update both the lite and pro versions of the software through normal WordPress update mechanisms, this release removes some clutter from the menu pages for Comet Cache. In short, now that we have a tighter integration with WordPress core, it's no longer necessary for Comet Cache to display update notifications in a custom way. See [Issue #829](https://github.com/websharks/comet-cache/issues/829).
14
+ - **UI Enhancement** (Pro): On pro version activation, display a notice that reminds site owners to configure their Pro Update Credentials so they'll be notified by WordPress about new versions of the pro software. See [Issue #477](https://github.com/websharks/comet-cache/issues/477).
15
+ - **New Pro Feature:** In the pro version it is now possible to define a list of GET request variable names that should be ignored entirely by Comet Cache. See: **Dashboard → Comet Cache → Plugin Options → GET Requests → List of GET Variable Names to Ignore**. As an example, this new feature makes it possible for site owners to pass query string variables associated with Google Analytics (i.e., `utm_*` variable names) without incurring a cache performance hit. See [Issue #639](https://github.com/websharks/comet-cache/issues/639).
16
+ - **Nonce Support** (Pro): In the pro version, when logged-in user caching is enabled, Comet Cache is now capable of intelligently caching pages that contain Nonce values ([numbers used once](https://cometcache.com/r/numbers-used-once-nonce/)). This allows for pages containing the WordPress Admin Bar to be cached without issue. It also improves compatibility with plugins like bbPress and BuddyPress, resulting in better performance and faster speeds for logged-in users. See [Issue #793](https://github.com/websharks/comet-cache/issues/793).
17
+ - **RevSlider Compat.:** This release includes a built-in exclusion rule for the HTML Compressor to allow for improved compatibility with the popular RevSlider plugin for WordPress. The new built-in exclusion rule looks for and automatically bypasses an important style tag that must be preserved for the RevSlider plugin to work in all scenarios; i.e., `<style id='rs-plugin-settings-inline-css'`. See [Issue #614](https://github.com/websharks/comet-cache/issues/614).
18
+ - **i18n Compat.** (Lite): This release makes all pro preview labels translatable by moving the labels that were previously defined in CSS only into HTML attribute values. See [Issue #808](https://github.com/websharks/comet-cache/issues/808).
19
+
20
  = v160917 =
21
 
22
+ - **New Feature** (Lite): The Clear Cache button is now available in the Admin Toolbar for the Lite version of Comet Cache.
23
  - **New Feature** (Pro): Comet Cache Pro is now fully compatible with [WordPress Automatic Background Updates](https://codex.wordpress.org/Configuring_Automatic_Background_Updates#Plugin_.26_Theme_Updates_via_Filter). If you enable automatic background updates for plugins, and you save valid Comet Cache Pro License Credentials in the _Comet Cache Pro → Plugin Options → Update Credentials_ panel, you will automatically receive Pro plugin updates. Props @jaswsinc. See [Issue #289](https://github.com/websharks/comet-cache/issues/289).
24
  - **Bug Fix**: In some scenarios Comet Cache might produce a false-positive "Warning: mkdir(): File exists" message when checking if the cache directory exists. Comet Cache now calls `clearstatcache()` and uses `file_exists()` instead of `is_dir()` to help make this check more robust. See [Issue #786](https://github.com/websharks/comet-cache/issues/786).
25
  - **Bug Fix**: Fixed a bug where the Comet Cache PHP requirements check would fail and produce a fatal error when upgrading from a version of Comet Cache that did not require an extension that is now required by newer releases. This would occur when, for example, the required PHP `mbstring` extension was missing. Props @jaswsinc for finding the bug. See [Issue #817](https://github.com/websharks/comet-cache/issues/817).
comet-cache.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /*
3
- Version: 160917
4
  Text Domain: comet-cache
5
  Plugin Name: Comet Cache
6
  Network: true
1
  <?php
2
  /*
3
+ Version: 161119
4
  Text Domain: comet-cache
5
  Plugin Name: Comet Cache
6
  Network: true
readme.txt CHANGED
@@ -1,8 +1,8 @@
1
  === Comet Cache ===
2
 
3
- Stable tag: 160917
4
  Requires at least: 4.2
5
- Tested up to: 4.7-alpha
6
  Text Domain: comet-cache
7
 
8
  License: GPLv2 or later
@@ -338,6 +338,25 @@ Requires WordPress v4.2+.
338
 
339
  == Changelog ==
340
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
341
  = v160917 =
342
 
343
  - **New Feature** (Lite): The Clear Cache button is now available in the Admin Toolbar for the Lite version of Comet Cache.
@@ -396,22 +415,4 @@ Requires WordPress v4.2+.
396
 
397
  - **Bug Fix**: Fixed a "PHP Fatal error: Undefined class constant 'CACHE_PATH_NO_SCHEME'" introduced by the previous release (v160416). This issue only affected sites where Feed Caching was enabled (_Comet Cache → Plugin Options → RSS, RDF, and Atom Feeds_). Props to MassimoD and @emanwebdev for reporting. See [Issue #739](https://github.com/websharks/comet-cache/issues/739).
398
 
399
- = v160416 =
400
-
401
- - **Enhancement**: Several PHP 5.4+ enhancements, most notably a conversion from PHP Closures to PHP Traits. See [Issue #635](https://github.com/websharks/comet-cache/issues/635).
402
- - **Enhancement**: Dashboard notices generated by Comet Cache now use the WordPress-style dismiss button to keep things consistent. See [Issue #719](https://github.com/websharks/comet-cache/issues/719).
403
- - **Enhancement**: Dashboard notices generated by Comet Cache are now compacted into a single notice that can be expanded to view details. This helps reduce the number of messages that appear when, for example, a Post is published or updated and several cache files are automatically cleared. Instead of showing a separate notice for each type of cache file that was cleared, a single notice is shown with a link to toggle the details. See [Issue #118](https://github.com/websharks/comet-cache/issues/118).
404
- - **Enhancement** (Pro): Improved the way the Auto-Cache Engine figures out the URL scheme (`http` vs `https`) that should be used when fetching the XML Sitemap. Instead of forcing `http`, whatever scheme is configured with the Home URL is now used. See [Issue #715](https://github.com/websharks/comet-cache/issues/715).
405
- - **Enhancement** (Pro): The Pro Plugin Updater page now includes a "Save All Changes" button at the bottom, allowing you to save changes to the updater configuration without actually running the plugin updater. Props @bridgeport @NoahjChampion @1wdtv. See [Issue #681](https://github.com/websharks/comet-cache/issues/681).
406
- - **Bug Fix**: Fixed a duplicated row of links on the Pro Plugin Updater page. See [Issue #696](https://github.com/websharks/comet-cache/issues/696).
407
- - **Bug Fix**: Fixed an issue where some browsers would report "Failed to parse SourceMap" errors in their console when browsing the Comet Cache Options page. This was related to `sourceMappingURL` comments in the minified JS/CSS files that were intended for development purposes. Props to @1wdtv for reporting. See [#732](https://github.com/websharks/comet-cache/issues/732).
408
- - **Bug Fix**: Fixed a UI bug in the Pro Preview that was causing the Manual Cache Clearing panel to not appear as part of the Pro Preview. Props @renzms. See [Issue #711](https://github.com/websharks/comet-cache/issues/711).
409
- - **Bug Fix** (Pro): Fixed a bug related to the Pro Updater where some users who had migrated from ZenCache Pro to Comet Cache Pro were seeing an invalid new version message. Props @renzms @jaswsinc. See [Issue #727](https://github.com/websharks/comet-cache/issues/727)
410
- - **Bug Fix** (Pro): Fixed a bug with the Pro Plugin Updater that resulted in "Unknown error. Please wait 15 minutes and try again." when attempting to update Comet Cache Pro. The issue affected sites on servers running an old version of cURL (< v7.36) and/or an old version of OpenSSL, which made them unable to connect to the Comet Cache Pro update server. The Pro Plugin Updater now attempts to connect to a secondary update server that is more compatible with older versions of cURL and OpenSSL. See [Issue #678](https://github.com/websharks/comet-cache/issues/678).
411
- - **Hooks/Filters**: Comet Cache now hooks into `plugins_loaded` instead of `after_setup_theme` when calling its own setup routine. This improves integration with other plugins that may be expecting the Comet Cache API functions to be available after `plugins_loaded`. Props to Frank Goossens (@futtta) from Autoptimize for helping with this. See [Issue #716](https://github.com/websharks/comet-cache/issues/716).
412
- - **Compatibility**: Fixed a compatibility issue for some themes and plugins that were using old AC Plugin code designed to work with Quick Cache. This fix adds some backwards compatibility support for Quick Cache, but note that the first release of Comet Cache dropped support for Quick Cache backwards compatibility in favor of ZenCache backwards compatibility. See [Issue #710](https://github.com/websharks/comet-cache/issues/710).
413
- - **Compatibility: Query Monitor.** The Query Monitor plugin was reporting false-positive errors indicating that many Comet Cache methods did not exist. This was due to how the Comet Cache codebase was utilizing PHP Closures, which Query Monitor had a hard time handling. The codebase has been refactored to use PHP Traits instead of Closures and now the Query Monitor plugin has no problem recognizing Comet Cache methods. Props to @NoahjChampion for reporting. See [Issue #686](https://github.com/websharks/comet-cache/issues/686).
414
- - **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).
415
- - **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).
416
-
417
- 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: 161119
4
  Requires at least: 4.2
5
+ Tested up to: 4.7
6
  Text Domain: comet-cache
7
 
8
  License: GPLv2 or later
338
 
339
  == Changelog ==
340
 
341
+ = v161119 =
342
+
343
+ - **Bug Fix:** Avoid browser autocomplete in configuration fields by adding `autocomplete="off"` to all form tags in Comet Cache menu pages. See [Issue #832](https://github.com/websharks/comet-cache/issues/832).
344
+ - **Bug Fix:** Fixed a broken link to the [Static CDN Filters tutorial for MaxCDN integration](http://cometcache.com/r/static-cdn-filters-maxcdn/). Props @kristineds. See [Issue #842](https://github.com/websharks/comet-cache/issues/842).
345
+ - **Bug Fix:** Multisite installations inside a subdirectory were broken by Apache Optimizations via `.htaccess` in some scenarios. Fixed in this release. See [Issue #798](https://github.com/websharks/comet-cache/issues/798).
346
+ - **Bug Fix:** Don't enqueue `Chart.js` unnecessarily in lite version of the software. See [Issue #830](https://github.com/websharks/comet-cache/issues/830).
347
+ - **Bug Fix:** Enhancing WooCommerce integration by listening to the `woocommerce_product_set_stock_status` hook in addition to the `woocommerce_product_set_stock` hook. See [Issue #674](https://github.com/websharks/comet-cache/issues/674).
348
+ - **Bug Fix** (Pro): Automatically dismiss any persistent update notifications whenever a new version of the software is recompiled; i.e., don't continue to show an upgrade notice whenever the software has just been updated by a site owner. See [Issue #806](https://github.com/websharks/comet-cache/issues/806).
349
+ - **Enhancement:** This version enhances the HTML comments left in the source code (HTML Debug Notes). When debug notes are enabled (i.e., HTML comments) they are now broken down into key/value pairs and tabulated for a cleaner display and easier debugging. See [Issue #790](https://github.com/websharks/comet-cache/issues/790).
350
+ - **Performance Enhancement:** For sites configured to allow query string variables into the cache, those variables are now sorted by key name internally to avoid duplicate cache files; i.e., whenever the order of query string variables changes from request to another, but with the same exact values. In short, Comet Cache now knows how to serve the same underlying cache file; i.e., from a previous request that may have had the same query string, just in a slightly different order. See [Issue #639](https://github.com/websharks/comet-cache/issues/639).
351
+ - **UI Enhancement:** The Comet Cache UI is now fully Responsive with an improved UI on laptop and mobile devices. Props @renzms. See [Issue #699](https://github.com/websharks/comet-cache/issues/699).
352
+ - **UI Enhancement:** This release improves the toggle link that allows you to see additional details whenever Comet Cache automatically clears more than one facet of the cache. See [Issue #837](https://github.com/websharks/comet-cache/issues/837) and [Issue #831](https://github.com/websharks/comet-cache/issues/831).
353
+ - **UI Enhancement** (Pro): Following improvements to the update API in a previous release of Comet Cache that made it possible to update both the lite and pro versions of the software through normal WordPress update mechanisms, this release removes some clutter from the menu pages for Comet Cache. In short, now that we have a tighter integration with WordPress core, it's no longer necessary for Comet Cache to display update notifications in a custom way. See [Issue #829](https://github.com/websharks/comet-cache/issues/829).
354
+ - **UI Enhancement** (Pro): On pro version activation, display a notice that reminds site owners to configure their Pro Update Credentials so they'll be notified by WordPress about new versions of the pro software. See [Issue #477](https://github.com/websharks/comet-cache/issues/477).
355
+ - **New Pro Feature:** In the pro version it is now possible to define a list of GET request variable names that should be ignored entirely by Comet Cache. See: **Dashboard → Comet Cache → Plugin Options → GET Requests → List of GET Variable Names to Ignore**. As an example, this new feature makes it possible for site owners to pass query string variables associated with Google Analytics (i.e., `utm_*` variable names) without incurring a cache performance hit. See [Issue #639](https://github.com/websharks/comet-cache/issues/639).
356
+ - **Nonce Support** (Pro): In the pro version, when logged-in user caching is enabled, Comet Cache is now capable of intelligently caching pages that contain Nonce values ([numbers used once](https://cometcache.com/r/numbers-used-once-nonce/)). This allows for pages containing the WordPress Admin Bar to be cached without issue. It also improves compatibility with plugins like bbPress and BuddyPress, resulting in better performance and faster speeds for logged-in users. See [Issue #793](https://github.com/websharks/comet-cache/issues/793).
357
+ - **RevSlider Compat.:** This release includes a built-in exclusion rule for the HTML Compressor to allow for improved compatibility with the popular RevSlider plugin for WordPress. The new built-in exclusion rule looks for and automatically bypasses an important style tag that must be preserved for the RevSlider plugin to work in all scenarios; i.e., `<style id='rs-plugin-settings-inline-css'`. See [Issue #614](https://github.com/websharks/comet-cache/issues/614).
358
+ - **i18n Compat.** (Lite): This release makes all pro preview labels translatable by moving the labels that were previously defined in CSS only into HTML attribute values. See [Issue #808](https://github.com/websharks/comet-cache/issues/808).
359
+
360
  = v160917 =
361
 
362
  - **New Feature** (Lite): The Clear Cache button is now available in the Admin Toolbar for the Lite version of Comet Cache.
415
 
416
  - **Bug Fix**: Fixed a "PHP Fatal error: Undefined class constant 'CACHE_PATH_NO_SCHEME'" introduced by the previous release (v160416). This issue only affected sites where Feed Caching was enabled (_Comet Cache → Plugin Options → RSS, RDF, and Atom Feeds_). Props to MassimoD and @emanwebdev for reporting. See [Issue #739](https://github.com/websharks/comet-cache/issues/739).
417
 
418
+ For older changelog history going back to 7+ years, 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:120%;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:600;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:600;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:13px;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
 
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{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;max-width:100%;box-sizing:border-box}.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}@media (max-width: 1199px){.plugin-menu-page img{float:none !important;display:block !important;margin:1em auto !important}.plugin-menu-page img:first-child{margin-top:0 !important}.plugin-menu-page img:last-child{margin-bottom:0 !important}}.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:120%;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}@media (max-width: 1199px){.plugin-menu-page label.switch-primary{margin-bottom:1em;display:block}}.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}@media (max-width: 1199px){.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% !important}}.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:600;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)}@media (max-width: 1199px){.plugin-menu-page button img{display:none !important}}.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-stats-button{float:right}@media (max-width: 1199px){.plugin-menu-page-heading .plugin-menu-page-stats-button{float:none;display:block;margin:auto}}.plugin-menu-page-heading .plugin-menu-page-restore-defaults{float:right;margin:0 1em 0 0}@media (max-width: 1199px){.plugin-menu-page-heading .plugin-menu-page-restore-defaults{float:none;clear:left;text-align:center;margin:0 auto}}.plugin-menu-page-heading .plugin-menu-page-panel-togglers{float:right;margin:0 1em 0 0}@media (max-width: 1199px){.plugin-menu-page-heading .plugin-menu-page-panel-togglers{display:none}}.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}@media (max-width: 1199px){.plugin-menu-page-heading .plugin-menu-page-upsells{float:none;clear:both;text-align:center;margin:0 auto 0 auto;padding:1em 0 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{float:right;clear:right;text-align:right;max-width:400px;margin:.5em 0 0}@media (max-width: 1199px){.plugin-menu-page-heading .plugin-menu-page-support-links{float:none;clear:both;text-align:center;margin:1em auto 1em auto}}.plugin-menu-page-heading .plugin-menu-page-support-links a{text-decoration:none;margin:0 0.5em;display:inline-block}.plugin-menu-page-heading .plugin-menu-page-mailing-list-links{float:right;clear:right;text-align:right;max-width:400px;margin:.5em 0 0}@media (max-width: 1199px){.plugin-menu-page-heading .plugin-menu-page-mailing-list-links{float:none;clear:both;text-align:center;margin:1em auto 1em auto}}.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}@media (max-width: 1199px){.plugin-menu-page-heading .plugin-menu-page-version{float:none;clear:both;text-align:center}}.plugin-menu-page-body{position:relative}.plugin-menu-page-section-heading{margin:1em}.plugin-menu-page-section-heading>small{margin:0;font-size:65%;font-style:italic;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:600;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[data-pro-version-only*=' ']{background:#216095}[data-pro-version-only*=' ']::after{font-variant:small-caps !important;font-family:sans-serif !important;content:attr(data-pro-version-only) !important;margin-left:15px;background:#216095;color:#FFFFFF;padding:0 5px 2px 5px;font-weight:normal}.plugin-menu-page-panel-heading[data-additional-pro-features*=' ']{background:#216095}[data-additional-pro-features*=' ']::after{font-variant:small-caps !important;font-family:sans-serif !important;content:attr(data-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:13px;color:#666}.plugin-menu-page-panel .plugin-menu-page-panel-body p.speed{font-size:120%;font-weight:bold;float:right}@media (max-width: 1199px){.plugin-menu-page-panel .plugin-menu-page-panel-body p.speed{display:none}}.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/includes/classes/AbsBase.php CHANGED
@@ -11,35 +11,35 @@ use WebSharks\CometCache\Interfaces;
11
  abstract class AbsBase implements Interfaces\Shared\NcDebugConsts, Interfaces\Shared\CachePathConsts
12
  {
13
  /**
14
- * @type null|plugin Plugin reference.
15
  *
16
  * @since 150422 Rewrite.
17
  */
18
  protected $plugin;
19
 
20
  /**
21
- * @type array Instance cache.
22
  *
23
  * @since 150422 Rewrite.
24
  */
25
  protected $cache = [];
26
 
27
  /**
28
- * @type array Global static cache ref.
29
  *
30
  * @since 150422 Rewrite.
31
  */
32
  protected $static = [];
33
 
34
  /**
35
- * @type array Global static cache.
36
  *
37
  * @since 150422 Rewrite.
38
  */
39
  protected static $global_static = [];
40
 
41
  /**
42
- * @type \stdClass Overload properties.
43
  *
44
  * @since 150422 Rewrite.
45
  */
@@ -185,7 +185,7 @@ abstract class AbsBase implements Interfaces\Shared\NcDebugConsts, Interfaces\Sh
185
 
186
  switch (gettype($_arg)) {
187
  case 'integer':
188
- $_key = (integer) $_arg;
189
  break; // Break switch handler.
190
 
191
  case 'double':
@@ -194,7 +194,7 @@ abstract class AbsBase implements Interfaces\Shared\NcDebugConsts, Interfaces\Sh
194
  break; // Break switch handler.
195
 
196
  case 'boolean':
197
- $_key = (integer) $_arg;
198
  break; // Break switch handler.
199
 
200
  case 'array':
11
  abstract class AbsBase implements Interfaces\Shared\NcDebugConsts, Interfaces\Shared\CachePathConsts
12
  {
13
  /**
14
+ * @var null|plugin Plugin reference.
15
  *
16
  * @since 150422 Rewrite.
17
  */
18
  protected $plugin;
19
 
20
  /**
21
+ * @var array Instance cache.
22
  *
23
  * @since 150422 Rewrite.
24
  */
25
  protected $cache = [];
26
 
27
  /**
28
+ * @var array Global static cache ref.
29
  *
30
  * @since 150422 Rewrite.
31
  */
32
  protected $static = [];
33
 
34
  /**
35
+ * @var array Global static cache.
36
  *
37
  * @since 150422 Rewrite.
38
  */
39
  protected static $global_static = [];
40
 
41
  /**
42
+ * @var \stdClass Overload properties.
43
  *
44
  * @since 150422 Rewrite.
45
  */
185
 
186
  switch (gettype($_arg)) {
187
  case 'integer':
188
+ $_key = (int) $_arg;
189
  break; // Break switch handler.
190
 
191
  case 'double':
194
  break; // Break switch handler.
195
 
196
  case 'boolean':
197
+ $_key = (int) $_arg;
198
  break; // Break switch handler.
199
 
200
  case 'array':
src/includes/classes/AbsBaseAp.php CHANGED
@@ -11,6 +11,7 @@ use WebSharks\CometCache\Traits;
11
  abstract class AbsBaseAp extends AbsBase
12
  {
13
  /*[.build.php-auto-generate-use-Traits]*/
 
14
  use Traits\Shared\BlogUtils;
15
  use Traits\Shared\CacheDirUtils;
16
  use Traits\Shared\CacheLockUtils;
11
  abstract class AbsBaseAp extends AbsBase
12
  {
13
  /*[.build.php-auto-generate-use-Traits]*/
14
+ use Traits\Shared\ArrayUtils;
15
  use Traits\Shared\BlogUtils;
16
  use Traits\Shared\CacheDirUtils;
17
  use Traits\Shared\CacheLockUtils;
src/includes/classes/MenuPageOptions.php CHANGED
@@ -20,7 +20,7 @@ class MenuPageOptions extends MenuPage
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";
25
 
26
  /* ----------------------------------------------------------------------------------------- */
@@ -30,11 +30,11 @@ class MenuPageOptions extends MenuPage
30
  if (is_multisite()) {
31
  echo '<button type="button" class="plugin-menu-page-wipe-cache" style="float:right; margin-left:15px;" title="'.esc_attr(__('Wipe Cache (Start Fresh); clears the cache for all sites in this network at once!', 'comet-cache')).'"'.
32
  ' data-action="'.esc_attr(add_query_arg(urlencode_deep(['page' => GLOBAL_NS, '_wpnonce' => wp_create_nonce(), GLOBAL_NS => ['wipeCache' => '1']]), self_admin_url('/admin.php'))).'">'.
33
- ' '.__('Wipe', 'comet-cache').' <img src="'.esc_attr($this->plugin->url('/src/client-s/images/wipe.png')).'" style="width:16px; height:16px;" /></button>'."\n";
34
  }
35
  echo ' <button type="button" class="plugin-menu-page-clear-cache" style="float:right;" title="'.esc_attr(__('Clear Cache (Start Fresh)', 'comet-cache').((is_multisite()) ? __('; affects the current site only.', 'comet-cache') : '')).'"'.
36
  ' data-action="'.esc_attr(add_query_arg(urlencode_deep(['page' => GLOBAL_NS, '_wpnonce' => wp_create_nonce(), GLOBAL_NS => ['clearCache' => '1']]), self_admin_url('/admin.php'))).'">'.
37
- ' '.__('Clear', 'comet-cache').' <img src="'.esc_attr($this->plugin->url('/src/client-s/images/clear.png')).'" style="width:16px; height:16px;" /></button>'."\n";
38
 
39
  echo ' <button type="button" class="plugin-menu-page-restore-defaults"'.// Restores default options.
40
  ' data-confirmation="'.esc_attr(__('Restore default plugin options? You will lose all of your current settings! Are you absolutely sure about this?', 'comet-cache')).'"'.
@@ -79,30 +79,16 @@ class MenuPageOptions extends MenuPage
79
 
80
  if (IS_PRO) {
81
  echo '<div class="plugin-menu-page-version">'."\n";
82
- echo ' '.sprintf(__('%1$s&trade; Pro v%2$s', 'comet-cache'), esc_html(NAME), esc_html(VERSION))."\n";
83
-
84
- if ($this->plugin->options['latest_pro_version'] && version_compare(VERSION, $this->plugin->options['latest_pro_version'], '<')) {
85
- if (!$this->plugin->options['pro_update_username'] || !$this->plugin->options['pro_update_password']) {
86
- echo '(<a href="#" style="font-weight:bold;" onclick="alert(\''.sprintf(__('A username and license key are required to complete an upgrade. See: %1$s → Plugin Options → \\\'Authentication for Automatic Updates\\\'. Enter the required details and try again.', 'comet-cache'), NAME).'\'); return false;">'.__('update available', 'comet-cache').'</a>)'."\n";
87
- } else {
88
- echo '(<a href="'.esc_attr(self_admin_url('/update-core.php')).'" style="font-weight:bold;">'.__('update available', 'comet-cache').'</a>)'."\n";
89
- }
90
- } else {
91
- echo '(<a href="'.esc_attr('https://cometcache.com/changelog/').'" target="_blank">'.__('changelog', 'comet-cache').'</a>)'."\n";
92
- }
93
  echo '</div>'."\n";
94
  } else { // For the lite version (default behavior).
95
  echo '<div class="plugin-menu-page-version">'."\n";
96
- echo ' '.sprintf(__('%1$s&trade; v%2$s', 'comet-cache'), esc_html(NAME), esc_html(VERSION))."\n";
97
-
98
- if ($this->plugin->options['latest_lite_version'] && version_compare(VERSION, $this->plugin->options['latest_lite_version'], '<')) {
99
- echo '(<a href="'.esc_attr(self_admin_url('/plugins.php')).'" style="font-weight:bold;">'.__('update available', 'comet-cache').'</a>)'."\n";
100
- } else {
101
- echo '(<a href="'.esc_attr('http://cometcache.com/changelog-lite/').'" target="_blank">'.__('changelog', 'comet-cache').'</a>)'."\n";
102
- }
103
  echo '</div>'."\n";
104
  }
105
- echo ' <img src="'.$this->plugin->url('/src/client-s/images/options-'.(IS_PRO ? 'pro' : 'lite').'.png').'" alt="'.esc_attr(__('Plugin Options', 'comet-cache')).'" />'."\n";
106
 
107
  echo '<div style="clear:both;"></div>'."\n";
108
 
@@ -208,8 +194,7 @@ class MenuPageOptions extends MenuPage
208
  echo ' </a>'."\n";
209
 
210
  echo ' <div class="plugin-menu-page-panel-body'.((!$this->plugin->options['enable']) ? ' open' : '').' clearfix">'."\n";
211
- echo ' <img src="'.esc_attr($this->plugin->url('/src/client-s/images/tach.png')).'" style="float:right; width:100px; margin-left:1em;" />'."\n";
212
- echo ' <p style="float:right; font-size:120%; font-weight:bold;">'.sprintf(__('%1$s&trade; = SPEED<em>!!</em>', 'comet-cache'), esc_html(NAME)).'</p>'."\n";
213
  echo ' <p><label class="switch-primary"><input type="radio" name="'.esc_attr(GLOBAL_NS).'[saveOptions][enable]" value="1"'.checked($this->plugin->options['enable'], '1', false).' /> '.sprintf(__('Yes, enable %1$s&trade;', 'comet-cache'), esc_html(NAME)).' <i class="si si-magic si-flip-horizontal"></i></label> &nbsp;&nbsp;&nbsp; <label><input type="radio" name="'.esc_attr(GLOBAL_NS).'[saveOptions][enable]" value="0"'.checked($this->plugin->options['enable'], '0', false).' /> '.__('No, disable.', 'comet-cache').'</label></p>'."\n";
214
  echo ' <p class="info" style="font-family:\'Georgia\', serif; font-size:110%; margin-top:1.5em;">'.sprintf(__('<strong>HUGE Time-Saver:</strong> Approx. 95%% of all WordPress sites running %1$s, simply enable it here; and that\'s it :-) <strong>No further configuration is necessary (really).</strong> All of the other options (down below) are already tuned for the BEST performance on a typical WordPress installation. Simply enable %1$s here and click "Save All Changes". If you get any warnings please follow the instructions given. Otherwise, you\'re good <i class="si si-smile-o"></i>. This plugin is designed to run just fine like it is. Take it for a spin right away; you can always fine-tune things later if you deem necessary.', 'comet-cache'), esc_html(NAME)).'</p>'."\n";
215
  echo ' <hr />'."\n";
@@ -230,13 +215,13 @@ class MenuPageOptions extends MenuPage
230
  /* ----------------------------------------------------------------------------------------- */
231
 
232
  if (IS_PRO || $this->plugin->isProPreview()) {
233
- echo '<div class="plugin-menu-page-panel">'."\n";
234
 
235
- echo ' <a href="#" class="plugin-menu-page-panel-heading'.(!IS_PRO ? ' pro-preview-feature' : '').'">'."\n";
236
  echo ' <i class="si si-sign-in"></i> '.__('Update Credentials', 'comet-cache')."\n";
237
  echo ' </a>'."\n";
238
 
239
- echo ' <div class="plugin-menu-page-panel-body clearfix">'."\n";
240
 
241
  echo ' <i class="si si-user si-4x" style="float:right; margin: 0 0 0 25px;"></i>'."\n";
242
 
@@ -296,7 +281,7 @@ class MenuPageOptions extends MenuPage
296
  if (IS_PRO || $this->plugin->isProPreview()) {
297
  echo '<div class="plugin-menu-page-panel">'."\n";
298
 
299
- echo ' <a href="#" class="plugin-menu-page-panel-heading'.(!IS_PRO ? ' pro-preview-feature' : '').'">'."\n";
300
  echo ' <i class="si si-broom"></i> '.__('Manual Cache Clearing', 'comet-cache')."\n";
301
  echo ' </a>'."\n";
302
 
@@ -371,7 +356,7 @@ class MenuPageOptions extends MenuPage
371
 
372
  echo '<div class="plugin-menu-page-panel'.(!IS_PRO && $this->plugin->isProPreview() ? ' pro-preview' : '').'">'."\n";
373
 
374
- echo ' <a href="#" class="plugin-menu-page-panel-heading'.((!IS_PRO && $this->plugin->isProPreview()) ? ' pro-preview-additional-features' : '').'">'."\n";
375
  echo ' <i class="si si-server"></i> '.__('Automatic Cache Clearing', 'comet-cache')."\n";
376
  echo ' </a>'."\n";
377
 
@@ -381,9 +366,9 @@ class MenuPageOptions extends MenuPage
381
  echo ' <img src="'.esc_attr($this->plugin->url('/src/client-s/images/auto-clear-ss.png')).'" class="screenshot" />'."\n";
382
  echo ' <p>'.sprintf(__('This is built into the %1$s plugin; i.e., this functionality is "always on". If you edit a Post/Page (or delete one), %1$s will automatically clear the cache file(s) associated with that content. This way a new updated version of the cache will be created automatically the next time this content is accessed. Simple updates like this occur each time you make changes in the Dashboard, and %1$s will notify you of these as they occur. %1$s monitors changes to Posts (of any kind, including Pages), Categories, Tags, Links, Themes (even Users), and more.', 'comet-cache'), esc_html(NAME)).'</p>'."\n";
383
  if (IS_PRO || $this->plugin->isProPreview()) {
384
- echo ' <div class="'.(!IS_PRO ? 'pro-preview-feature' : '').'">'."\n";
385
  echo ' <p><select name="'.esc_attr(GLOBAL_NS).'[saveOptions][change_notifications_enable]" class="-no-if-enabled" style="width:auto;">'."\n";
386
- echo ' <option value="1"'.selected($this->plugin->options['change_notifications_enable'], '1', false).'>'.sprintf(__('Yes, enable %1$s notifications in the Dashboard when changes are detected &amp; one or more cache files are cleared automatically.', 'comet-cache'), esc_html(NAME)).'</option>'."\n";
387
  echo ' <option value="0"'.selected($this->plugin->options['change_notifications_enable'], '0', false).'>'.sprintf(__('No, I don\'t want to know (don\'t really care) what %1$s is doing behind-the-scene.', 'comet-cache'), esc_html(NAME)).'</option>'."\n";
388
  echo ' </select></p>'."\n";
389
  echo ' </div>'."\n";
@@ -471,7 +456,7 @@ class MenuPageOptions extends MenuPage
471
 
472
  if (IS_PRO || $this->plugin->isProPreview()) {
473
  echo ' <hr />'."\n";
474
- echo ' <h3 class="'.(!IS_PRO ? 'pro-preview-feature' : '').'">'.__('Misc. Auto-Clear Options', 'comet-cache').'</h3>'."\n";
475
  echo ' <h4 style="margin-bottom:0;">'.__('Auto-Clear a List of Custom URLs Too?', 'comet-cache').'</h4>'."\n";
476
  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";
477
  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";
@@ -486,7 +471,7 @@ class MenuPageOptions extends MenuPage
486
  if (IS_PRO || $this->plugin->isProPreview()) {
487
  echo '<div class="plugin-menu-page-panel">'."\n";
488
 
489
- echo ' <a href="#" class="plugin-menu-page-panel-heading'.(!IS_PRO ? ' pro-preview-feature' : '').'">'."\n";
490
  echo ' <i class="si si-pie-chart"></i> '.__('Cache-Related Statistics', 'comet-cache')."\n";
491
  echo ' </a>'."\n";
492
 
@@ -552,7 +537,7 @@ class MenuPageOptions extends MenuPage
552
 
553
  echo '<div class="plugin-menu-page-panel'.(!IS_PRO && $this->plugin->isProPreview() ? ' pro-preview' : '').'">'."\n";
554
 
555
- echo ' <a href="#" class="plugin-menu-page-panel-heading'.((!IS_PRO && $this->plugin->isProPreview()) ? ' pro-preview-additional-features' : '').'">'."\n";
556
  echo ' <i class="si si-clock-o"></i> '.__('Cache Expiration Time', 'comet-cache')."\n";
557
  echo ' </a>'."\n";
558
 
@@ -581,7 +566,7 @@ class MenuPageOptions extends MenuPage
581
  $_sys_getloadavg_unavailable = ($this->plugin->isProPreview() ? false : !$this->plugin->sysLoadAverages());
582
  echo ' <div>'."\n";
583
  echo ' <hr />'."\n";
584
- echo ' <h3 class="'.(!IS_PRO ? 'pro-preview-feature' : '').'" style="'.($_sys_getloadavg_unavailable ? 'opacity: 0.5;' : '').'">'.__('Disable Cache Expiration If Server Load Average is High?', 'comet-cache').'</h3>'."\n";
585
  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";
586
  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";
587
  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";
@@ -635,16 +620,16 @@ class MenuPageOptions extends MenuPage
635
  if (IS_PRO || $this->plugin->isProPreview()) {
636
  echo '<div class="plugin-menu-page-panel'.(!IS_PRO ? ' pro-preview' : '').'">'."\n";
637
 
638
- echo ' <a href="#" class="plugin-menu-page-panel-heading'.(!IS_PRO ? ' pro-preview-feature' : '').'">'."\n";
639
  echo ' <i class="si si-octi-organization"></i> '.__('Logged-In Users', 'comet-cache')."\n";
640
  echo ' </a>'."\n";
641
 
642
  echo ' <div class="plugin-menu-page-panel-body clearfix">'."\n";
643
  echo ' <i class="si si-group si-4x" style="float:right; margin: 0 0 0 25px;"></i>'."\n";
644
  echo ' <h3>'.__('Caching Enabled for Logged-In Users &amp; Comment Authors?', 'comet-cache').'</h3>'."\n";
645
- 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";
646
  echo ' <i class="si si-sitemap si-4x" style="float:right; margin: 0 0 0 25px;"></i>'."\n";
647
- 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";
648
  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";
649
  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";
650
  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";
@@ -656,26 +641,27 @@ class MenuPageOptions extends MenuPage
656
  if ($this->plugin->options['when_logged_in'] === '1' && $this->plugin->applyWpFilters(GLOBAL_NS.'_when_logged_in_no_admin_bar', true)) {
657
  echo '<p class="warning">'.sprintf(__('<strong>Warning:</strong> Whenever you enable caching for logged-in users (without a separate cache for each user), the WordPress Admin Bar <em>must</em> be disabled to prevent one user from seeing another user\'s details in the Admin Bar. <strong>Given your current configuration, %1$s will automatically hide the WordPress Admin Bar on the front-end of your site.</strong>', 'comet-cache'), esc_html(NAME)).'</p>'."\n";
658
  }
659
- 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";
660
- 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";
661
  echo ' <hr />'."\n";
 
662
  echo ' <div class="plugin-menu-page-panel-if-enabled -logged-in-users-options">'."\n";
 
 
 
 
 
 
 
 
663
  echo ' <h3>'.__('Static CDN Filters Enabled for Logged-In Users &amp; Comment Authors?', 'comet-cache').'</h3>'."\n";
664
- 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";
665
  echo ' <p><select name="'.esc_attr(GLOBAL_NS).'[saveOptions][cdn_when_logged_in]">'."\n";
666
  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";
667
  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";
668
  echo ' </select></p>'."\n";
669
  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";
670
  echo ' <hr />'."\n";
671
- echo ' <h3>'.__('Disable the Admin Toolbar for Logged-In Users &amp; Comment Authors?', 'comet-cache').'</h3>'."\n";
672
- 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";
673
- echo ' <p><select name="'.esc_attr(GLOBAL_NS).'[saveOptions][when_logged_in_admin_bar]">'."\n";
674
- 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";
675
- 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";
676
- echo ' </select></p>'."\n";
677
- 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";
678
- echo ' <hr />'."\n";
679
  echo ' <h3>'.__('Enable HTML Compression for Logged-In Users?', 'comet-cache').'</h3>'."\n";
680
  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";
681
  echo ' <p><select name="'.esc_attr(GLOBAL_NS).'[saveOptions][htmlc_when_logged_in]">'."\n";
@@ -689,22 +675,33 @@ class MenuPageOptions extends MenuPage
689
  }
690
  /* ----------------------------------------------------------------------------------------- */
691
 
692
- echo '<div class="plugin-menu-page-panel">'."\n";
693
 
694
- echo ' <a href="#" class="plugin-menu-page-panel-heading">'."\n";
695
  echo ' <i class="si si-question-circle"></i> '.__('GET Requests', 'comet-cache')."\n";
696
  echo ' </a>'."\n";
697
 
698
  echo ' <div class="plugin-menu-page-panel-body clearfix">'."\n";
 
699
  echo ' <i class="si si-question-circle si-4x" style="float:right; margin: 0 0 0 25px;"></i>'."\n";
700
  echo ' <h3>'.__('Caching Enabled for GET (Query String) Requests?', 'comet-cache').'</h3>'."\n";
701
- echo ' <p>'.__('This should almost ALWAYS be set to <code>No</code>. UNLESS, you\'re using unfriendly Permalinks. In other words, if all of your URLs contain a query string (e.g., <code>/?key=value</code>); you\'re using unfriendly Permalinks. Ideally, you would refrain from doing this; and instead, update your Permalink options immediately; which also optimizes your site for search engines. That being said, if you really want to use unfriendly Permalinks, and ONLY if you\'re using unfriendly Permalinks, you should set this to <code>Yes</code>; and don\'t worry too much, the sky won\'t fall on your head :-)', 'comet-cache').'</p>'."\n";
702
  echo ' <p><select name="'.esc_attr(GLOBAL_NS).'[saveOptions][get_requests]">'."\n";
703
  echo ' <option value="0"'.selected($this->plugin->options['get_requests'], '0', false).'>'.__('No, do NOT cache (or serve a cache file) when a query string is present.', 'comet-cache').'</option>'."\n";
704
  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";
705
  echo ' </select></p>'."\n";
706
- 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";
707
- 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";
 
 
 
 
 
 
 
 
 
 
708
  echo ' </div>'."\n";
709
 
710
  echo '</div>'."\n";
@@ -736,7 +733,7 @@ class MenuPageOptions extends MenuPage
736
  echo '<div class="plugin-menu-page-panel">'."\n";
737
 
738
  echo ' <a href="#" class="plugin-menu-page-panel-heading">'."\n";
739
- echo ' <i class="si si-feed"></i> '.__('RSS, RDF, and Atom Feeds', 'comet-cache')."\n";
740
  echo ' </a>'."\n";
741
 
742
  echo ' <div class="plugin-menu-page-panel-body clearfix">'."\n";
@@ -758,12 +755,10 @@ class MenuPageOptions extends MenuPage
758
  ((defined('SUBDOMAIN_INSTALL') && SUBDOMAIN_INSTALL) || $this->plugin->canConsiderDomainMapping());
759
 
760
  if ($this->plugin->applyWpFilters(GLOBAL_NS.'_exclude_hosts_option_enable', $exclude_hosts_option_enable)) {
761
- // Display option panel for Host Exclusion Patterns.
762
-
763
  echo '<div class="plugin-menu-page-panel">'."\n";
764
 
765
  echo ' <a href="#" class="plugin-menu-page-panel-heading">'."\n";
766
- echo ' <i class="si si-ban"></i> '.__('Host Exclusion Patterns', 'comet-cache')."\n";
767
  echo ' </a>'."\n";
768
 
769
  echo ' <div class="plugin-menu-page-panel-body clearfix">'."\n";
@@ -784,7 +779,7 @@ class MenuPageOptions extends MenuPage
784
  echo '<div class="plugin-menu-page-panel">'."\n";
785
 
786
  echo ' <a href="#" class="plugin-menu-page-panel-heading">'."\n";
787
- echo ' <i class="si si-ban"></i> '.__('URI Exclusion Patterns', 'comet-cache')."\n";
788
  echo ' </a>'."\n";
789
 
790
  echo ' <div class="plugin-menu-page-panel-body clearfix">'."\n";
@@ -806,7 +801,7 @@ class MenuPageOptions extends MenuPage
806
  echo '<div class="plugin-menu-page-panel">'."\n";
807
 
808
  echo ' <a href="#" class="plugin-menu-page-panel-heading">'."\n";
809
- echo ' <i class="si si-ban"></i> '.__('HTTP Referrer Exclusion Patterns', 'comet-cache')."\n";
810
  echo ' </a>'."\n";
811
 
812
  echo ' <div class="plugin-menu-page-panel-body clearfix">'."\n";
@@ -824,7 +819,7 @@ class MenuPageOptions extends MenuPage
824
  echo '<div class="plugin-menu-page-panel">'."\n";
825
 
826
  echo ' <a href="#" class="plugin-menu-page-panel-heading">'."\n";
827
- echo ' <i class="si si-ban"></i> '.__('User-Agent Exclusion Patterns', 'comet-cache')."\n";
828
  echo ' </a>'."\n";
829
 
830
  echo ' <div class="plugin-menu-page-panel-body clearfix">'."\n";
@@ -842,7 +837,7 @@ class MenuPageOptions extends MenuPage
842
  if (IS_PRO || $this->plugin->isProPreview()) {
843
  echo '<div class="plugin-menu-page-panel'.(!IS_PRO ? ' pro-preview' : '').'">'."\n";
844
 
845
- echo ' <a href="#" class="plugin-menu-page-panel-heading'.(!IS_PRO ? ' pro-preview-feature' : '').'">'."\n";
846
  echo ' <i class="si si-sitemap"></i> '.__('Auto-Cache Engine', 'comet-cache')."\n";
847
  echo ' </a>'."\n";
848
 
@@ -896,7 +891,7 @@ class MenuPageOptions extends MenuPage
896
  if (IS_PRO || $this->plugin->isProPreview()) {
897
  echo '<div class="plugin-menu-page-panel'.(!IS_PRO ? ' pro-preview' : '').'">'."\n";
898
 
899
- echo ' <a href="#" class="plugin-menu-page-panel-heading'.(!IS_PRO ? ' pro-preview-feature' : '').'">'."\n";
900
  echo ' <i class="si si-html5"></i> '.__('HTML Compression', 'comet-cache')."\n";
901
  echo ' </a>'."\n";
902
 
@@ -910,7 +905,6 @@ class MenuPageOptions extends MenuPage
910
  echo ' <option value="0"'.(!IS_PRO ? '' : selected($this->plugin->options['htmlc_enable'], '0', false)).'>'.__('No, do NOT compress HTML/CSS/JS code at runtime.', 'comet-cache').'</option>'."\n";
911
  echo ' <option value="1"'.(!IS_PRO ? ' selected' : selected($this->plugin->options['htmlc_enable'], '1', false)).'>'.__('Yes, I want to compress HTML/CSS/JS for blazing fast speeds.', 'comet-cache').'</option>'."\n";
912
  echo ' </select></p>'."\n";
913
- echo ' <p class="info" style="display:block;">'.__('<strong>Note:</strong> This is experimental. Please <a href="https://github.com/websharks/comet-cache/issues" target="_blank">report issues here</a>.', 'comet-cache').'</p>'."\n";
914
  echo ' <hr />'."\n";
915
  echo ' <div class="plugin-menu-page-panel-if-enabled -htmlc-options">'."\n";
916
  echo ' <h3>'.__('HTML Compression Options', 'comet-cache').'</h3>'."\n";
@@ -976,12 +970,12 @@ class MenuPageOptions extends MenuPage
976
  if (IS_PRO || $this->plugin->isProPreview()) {
977
  echo '<div class="plugin-menu-page-panel'.(!IS_PRO ? ' pro-preview' : '').'">'."\n";
978
 
979
- echo ' <a href="#" class="plugin-menu-page-panel-heading'.(!IS_PRO ? ' pro-preview-feature' : '').'">'."\n";
980
  echo ' <i class="si si-cloud"></i> '.__('Static CDN Filters', 'comet-cache')."\n";
981
  echo ' </a>'."\n";
982
 
983
  echo ' <div class="plugin-menu-page-panel-body clearfix">'."\n";
984
- echo ' <button type="button" class="plugin-menu-page-clear-cdn-cache" style="float:right; margin:0 0 1em 1em;" title="'.esc_attr(__('Clear CDN Cache (Bump CDN Invalidation Counter)', 'comet-cache')).'">'.__('Clear CDN Cache', 'comet-cache').' <img src="'.esc_attr($this->plugin->url('/src/client-s/images/clear.png')).'" style="width:16px; height:16px;" /></button>'."\n";
985
  echo ' <h3>'.__('Enable Static CDN Filters (e.g., MaxCDN/CloudFront)?', 'comet-cache').'</h3>'."\n";
986
  echo ' <p>'.sprintf(__('This feature allows you to serve some and/or ALL static files on your site from a CDN of your choosing. This is made possible through content/URL filters exposed by WordPress and implemented by %1$s. All it requires is that you setup a CDN host name sourced by your WordPress installation domain. You enter that CDN host name below and %1$s will do the rest! Super easy, and it doesn\'t require any DNS changes either. :-) Please <a href="http://cometcache.com/r/static-cdn-filters-general-instructions/" target="_blank">click here</a> for a general set of instructions.', 'comet-cache'), esc_html(NAME)).'</p>'."\n";
987
  echo ' <p>'.__('<strong>What\'s a CDN?</strong> It\'s a Content Delivery Network (i.e., a network of optimized servers) designed to cache static resources served from your site (e.g., JS/CSS/images and other static files) onto it\'s own servers, which are located strategically in various geographic areas around the world. Integrating a CDN for static files can dramatically improve the speed and performance of your site, lower the burden on your own server, and reduce latency associated with visitors attempting to access your site from geographic areas of the world that might be very far away from the primary location of your own web servers.', 'comet-cache').'</p>'."\n";
@@ -1078,7 +1072,7 @@ class MenuPageOptions extends MenuPage
1078
  if ($is_apache || $this->plugin->isProPreview()) {
1079
  echo '<div class="plugin-menu-page-panel'.(!IS_PRO && $this->plugin->isProPreview() ? ' pro-preview' : '').'">'."\n";
1080
 
1081
- echo ' <a href="#" class="plugin-menu-page-panel-heading'.((!IS_PRO && $this->plugin->isProPreview()) ? ' pro-preview-additional-features' : '').'">'."\n";
1082
  echo ' <i class="si si-server"></i> '.__('Apache Optimizations', 'comet-cache')."\n";
1083
  echo ' </a>'."\n";
1084
 
@@ -1111,7 +1105,7 @@ class MenuPageOptions extends MenuPage
1111
 
1112
  if (IS_PRO || $this->plugin->isProPreview()) {
1113
  echo ' <hr />'."\n";
1114
- echo ' <h3 class="'.(!IS_PRO ? 'pro-preview-feature' : '').'">'.__('Leverage Browser Caching?', 'comet-cache').'</h3>'."\n";
1115
  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";
1116
  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 visitor\'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";
1117
  echo ' <p><select name="'.esc_attr(GLOBAL_NS).'[saveOptions][htaccess_browser_caching_enable]" data-target=".-htaccess-browser-caching-enable-options">'."\n";
@@ -1127,7 +1121,7 @@ class MenuPageOptions extends MenuPage
1127
 
1128
  if ((IS_PRO && !empty($GLOBALS['wp_rewrite']->permalink_structure)) || $this->plugin->isProPreview()) {
1129
  echo ' <hr />'."\n";
1130
- echo ' <h3 class="'.(!IS_PRO ? 'pro-preview-feature' : '').'">'.__('Enforce Canonical URLs?', 'comet-cache').'</h3>'."\n";
1131
  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";
1132
  echo ' <p><select name="'.esc_attr(GLOBAL_NS).'[saveOptions][htaccess_enforce_canonical_urls]" data-target=".-htaccess-enforce-canonical-urls-options">'."\n";
1133
  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";
@@ -1146,7 +1140,7 @@ class MenuPageOptions extends MenuPage
1146
 
1147
  if ((IS_PRO && $this->plugin->options['cdn_enable']) || $this->plugin->isProPreview()) {
1148
  echo ' <hr />'."\n";
1149
- echo ' <h3 class="'.(!IS_PRO ? 'pro-preview-feature' : '').'">'.__('Send Access-Control-Allow-Origin Header?', 'comet-cache').'</h3>'."\n";
1150
  if ($this->plugin->options['cdn_enable'] && !$this->plugin->options['htaccess_access_control_allow_origin']) {
1151
  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";
1152
  }
@@ -1170,7 +1164,7 @@ class MenuPageOptions extends MenuPage
1170
  if (IS_PRO || $this->plugin->isProPreview()) {
1171
  echo '<div class="plugin-menu-page-panel'.(!IS_PRO ? ' pro-preview' : '').'">'."\n";
1172
 
1173
- echo ' <a href="#" class="plugin-menu-page-panel-heading'.(!IS_PRO ? ' pro-preview-feature' : '').'">'."\n";
1174
  echo ' <i class="si si-octi-versions"></i> '.__('Dynamic Version Salt', 'comet-cache')."\n";
1175
  echo ' </a>'."\n";
1176
 
@@ -1180,11 +1174,11 @@ class MenuPageOptions extends MenuPage
1180
  echo ' <p>'.sprintf(__('<em>Note: Understanding the %1$s <a href="http://cometcache.com/r/kb-branched-cache-structure/" target="_blank">Branched Cache Structure</a> is a prerequisite to understanding how Dynamic Version Salts are added to the mix.</em>', 'comet-cache'), esc_html(NAME)).'</p>'."\n";
1181
  echo ' <p>'.__('A Version Salt gives you the ability to dynamically create multiple variations of the cache, and those dynamic variations will be served on subsequent visits; e.g., if a visitor has a specific cookie (of a certain value) they will see pages which were cached with that version (i.e., w/ that Version Salt: the value of the cookie). A Version Salt can really be anything.', 'comet-cache').'</p>'."\n";
1182
  echo ' <p>'.__('A Version Salt can be a single variable like <code>$_COOKIE[\'my_cookie\']</code>, or it can be a combination of multiple variables, like <code>$_COOKIE[\'my_cookie\'].$_COOKIE[\'my_other_cookie\']</code>. (When using multiple variables, please separate them with a dot, as shown in the example.)', 'comet-cache').'</p>'."\n";
1183
- echo ' <p>'.__('Experts could even use PHP ternary expressions that evaluate into something. For example: <code>((preg_match(\'/iPhone/i\', $_SERVER[\'HTTP_USER_AGENT\'])) ? \'iPhones\' : \'\')</code>. This would force a separate version of the cache to be created for iPhones (e.g., <code>/cache/PROTOCOL/HOST/REQUEST-URI.v/iPhones.html</code>).', 'comet-cache').'</p>'."\n";
1184
  echo ' <p>'.__('For more documentation, please see <a href="http://cometcache.com/r/kb-dynamic-version-salts/" target="_blank">Dynamic Version Salts</a>.', 'comet-cache').'</p>'."\n";
1185
  echo ' <hr />'."\n";
1186
  echo ' <h3>'.sprintf(__('Create a Dynamic Version Salt For %1$s? &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-size:90%%; opacity:0.5;">150%% OPTIONAL</span>', 'comet-cache'), esc_html(NAME)).'</h3>'."\n";
1187
- echo ' <table style="width:100%;"><tr><td style="width:1px; font-weight:bold; white-space:nowrap;">/cache/PROTOCOL/HOST/REQUEST_URI.</td><td><input type="text" name="'.esc_attr(GLOBAL_NS).'[saveOptions][version_salt]" value="'.esc_attr($this->plugin->options['version_salt']).'" class="monospace" placeholder="$_COOKIE[\'my_cookie\']" /></td><td style="width:1px; font-weight:bold; white-space:nowrap;"></td></tr></table>'."\n";
1188
  echo ' <p class="info" style="display:block;">'.__('<a href="http://php.net/manual/en/language.variables.superglobals.php" target="_blank">Super Globals</a> work here; <a href="http://codex.wordpress.org/Editing_wp-config.php#table_prefix" target="_blank"><code>$GLOBALS[\'table_prefix\']</code></a> is a popular one.<br />Or, perhaps a PHP Constant defined in <code>/wp-config.php</code>; such as <code>WPLANG</code> or <code>DB_HOST</code>.', 'comet-cache').'</p>'."\n";
1189
  echo ' <p class="notice" style="display:block;">'.__('<strong>Important:</strong> your Version Salt is scanned for PHP syntax errors via <a href="http://phpcodechecker.com/" target="_blank"><code>phpCodeChecker.com</code></a>. If errors are found, you\'ll receive a notice in the Dashboard.', 'comet-cache').'</p>'."\n";
1190
  echo ' <p class="info" style="display:block;">'.__('If you\'ve enabled a separate cache for each user (optional) that\'s perfectly OK. A Version Salt works with user caching too.', 'comet-cache').'</p>'."\n";
@@ -1217,7 +1211,7 @@ class MenuPageOptions extends MenuPage
1217
  if (IS_PRO || $this->plugin->isProPreview()) {
1218
  echo '<div class="plugin-menu-page-panel'.(!IS_PRO ? ' pro-preview' : '').'">'."\n";
1219
 
1220
- echo ' <a href="#" class="plugin-menu-page-panel-heading'.(!IS_PRO ? ' pro-preview-feature' : '').'">'."\n";
1221
  echo ' <i class="si si-arrow-circle-o-up"></i> '.__('Import/Export Options', 'comet-cache')."\n";
1222
  echo ' </a>'."\n";
1223
 
@@ -1230,7 +1224,7 @@ class MenuPageOptions extends MenuPage
1230
  echo ' <h3>'.sprintf(__('Export Existing Options from this %1$s Installation?', 'comet-cache'), esc_html(NAME)).'</h3>'."\n";
1231
  echo ' <button type="button" class="plugin-menu-page-export-options" style="float:right; margin: 0 0 0 25px;"'.// Exports existing options from this installation.
1232
  ' data-action="'.esc_attr(add_query_arg(urlencode_deep(['page' => GLOBAL_NS, '_wpnonce' => wp_create_nonce(), GLOBAL_NS => ['exportOptions' => '1']]), self_admin_url('/admin.php'))).'">'.
1233
- ' '.sprintf(__('%1$s-options.json', 'comet-cache'), GLOBAL_NS).' <i class="si si-arrow-circle-o-down"></i></button>'."\n";
1234
  echo ' <p>'.sprintf(__('Download your existing options and import them all into another %1$s installation; saves time on future installs.', 'comet-cache'), esc_html(NAME)).'</p>'."\n";
1235
  echo ' </div>'."\n";
1236
 
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" autocomplete="off"'.
24
  ' action="'.esc_attr(add_query_arg(urlencode_deep(['page' => GLOBAL_NS, '_wpnonce' => wp_create_nonce()]), self_admin_url('/admin.php'))).'">'."\n";
25
 
26
  /* ----------------------------------------------------------------------------------------- */
30
  if (is_multisite()) {
31
  echo '<button type="button" class="plugin-menu-page-wipe-cache" style="float:right; margin-left:15px;" title="'.esc_attr(__('Wipe Cache (Start Fresh); clears the cache for all sites in this network at once!', 'comet-cache')).'"'.
32
  ' data-action="'.esc_attr(add_query_arg(urlencode_deep(['page' => GLOBAL_NS, '_wpnonce' => wp_create_nonce(), GLOBAL_NS => ['wipeCache' => '1']]), self_admin_url('/admin.php'))).'">'.
33
+ ' '.__('Wipe', 'comet-cache').' <img src="'.esc_attr($this->plugin->url('/src/client-s/images/wipe.png')).'" style="width:16px; height:16px; display:inline-block;" /></button>'."\n";
34
  }
35
  echo ' <button type="button" class="plugin-menu-page-clear-cache" style="float:right;" title="'.esc_attr(__('Clear Cache (Start Fresh)', 'comet-cache').((is_multisite()) ? __('; affects the current site only.', 'comet-cache') : '')).'"'.
36
  ' data-action="'.esc_attr(add_query_arg(urlencode_deep(['page' => GLOBAL_NS, '_wpnonce' => wp_create_nonce(), GLOBAL_NS => ['clearCache' => '1']]), self_admin_url('/admin.php'))).'">'.
37
+ ' '.__('Clear', 'comet-cache').' <img src="'.esc_attr($this->plugin->url('/src/client-s/images/clear.png')).'" style="width:16px; height:16px; display:inline-block;" /></button>'."\n";
38
 
39
  echo ' <button type="button" class="plugin-menu-page-restore-defaults"'.// Restores default options.
40
  ' data-confirmation="'.esc_attr(__('Restore default plugin options? You will lose all of your current settings! Are you absolutely sure about this?', 'comet-cache')).'"'.
79
 
80
  if (IS_PRO) {
81
  echo '<div class="plugin-menu-page-version">'."\n";
82
+ echo sprintf(__('%1$s&trade; Pro v%2$s', 'comet-cache'), esc_html(NAME), esc_html(VERSION))."\n";
83
+ echo '(<a href="'.esc_attr('https://cometcache.com/changelog/').'" target="_blank">'.__('changelog', 'comet-cache').'</a>)'."\n";
 
 
 
 
 
 
 
 
 
84
  echo '</div>'."\n";
85
  } else { // For the lite version (default behavior).
86
  echo '<div class="plugin-menu-page-version">'."\n";
87
+ echo sprintf(__('%1$s&trade; v%2$s', 'comet-cache'), esc_html(NAME), esc_html(VERSION))."\n";
88
+ echo '(<a href="'.esc_attr('http://cometcache.com/changelog-lite/').'" target="_blank">'.__('changelog', 'comet-cache').'</a>)'."\n";
 
 
 
 
 
89
  echo '</div>'."\n";
90
  }
91
+ echo ' <img src="'.$this->plugin->url('/src/client-s/images/options-'.(IS_PRO ? 'pro' : 'lite').'.png').'" alt="'.esc_attr(__('Plugin Options', 'comet-cache')).'" />'."\n";
92
 
93
  echo '<div style="clear:both;"></div>'."\n";
94
 
194
  echo ' </a>'."\n";
195
 
196
  echo ' <div class="plugin-menu-page-panel-body'.((!$this->plugin->options['enable']) ? ' open' : '').' clearfix">'."\n";
197
+ echo ' <p class="speed"><img src="'.esc_attr($this->plugin->url('/src/client-s/images/tach.png')).'" style="float:right; width:100px; margin-left:1em;" />'.sprintf(__('%1$s&trade; = SPEED<em>!!</em>', 'comet-cache'), esc_html(NAME)).'</p>'."\n";
 
198
  echo ' <p><label class="switch-primary"><input type="radio" name="'.esc_attr(GLOBAL_NS).'[saveOptions][enable]" value="1"'.checked($this->plugin->options['enable'], '1', false).' /> '.sprintf(__('Yes, enable %1$s&trade;', 'comet-cache'), esc_html(NAME)).' <i class="si si-magic si-flip-horizontal"></i></label> &nbsp;&nbsp;&nbsp; <label><input type="radio" name="'.esc_attr(GLOBAL_NS).'[saveOptions][enable]" value="0"'.checked($this->plugin->options['enable'], '0', false).' /> '.__('No, disable.', 'comet-cache').'</label></p>'."\n";
199
  echo ' <p class="info" style="font-family:\'Georgia\', serif; font-size:110%; margin-top:1.5em;">'.sprintf(__('<strong>HUGE Time-Saver:</strong> Approx. 95%% of all WordPress sites running %1$s, simply enable it here; and that\'s it :-) <strong>No further configuration is necessary (really).</strong> All of the other options (down below) are already tuned for the BEST performance on a typical WordPress installation. Simply enable %1$s here and click "Save All Changes". If you get any warnings please follow the instructions given. Otherwise, you\'re good <i class="si si-smile-o"></i>. This plugin is designed to run just fine like it is. Take it for a spin right away; you can always fine-tune things later if you deem necessary.', 'comet-cache'), esc_html(NAME)).'</p>'."\n";
200
  echo ' <hr />'."\n";
215
  /* ----------------------------------------------------------------------------------------- */
216
 
217
  if (IS_PRO || $this->plugin->isProPreview()) {
218
+ echo '<div class="plugin-menu-page-panel" id="'.esc_attr(SLUG_TD.'-configure-pro-updater').'">'."\n";
219
 
220
+ echo ' <a href="#" class="plugin-menu-page-panel-heading'.(!empty($_REQUEST[GLOBAL_NS.'_configure_pro_updater']) ? ' open' : '').'" data-pro-version-only="'.(!IS_PRO ? __('pro version only', 'comet-cache') : '').'">'."\n";
221
  echo ' <i class="si si-sign-in"></i> '.__('Update Credentials', 'comet-cache')."\n";
222
  echo ' </a>'."\n";
223
 
224
+ echo ' <div class="plugin-menu-page-panel-body'.(!empty($_REQUEST[GLOBAL_NS.'_configure_pro_updater']) ? ' open' : '').' clearfix">'."\n";
225
 
226
  echo ' <i class="si si-user si-4x" style="float:right; margin: 0 0 0 25px;"></i>'."\n";
227
 
281
  if (IS_PRO || $this->plugin->isProPreview()) {
282
  echo '<div class="plugin-menu-page-panel">'."\n";
283
 
284
+ echo ' <a href="#" class="plugin-menu-page-panel-heading" data-pro-version-only="'.(!IS_PRO ? __('pro version only', 'comet-cache') : '').'">'."\n";
285
  echo ' <i class="si si-broom"></i> '.__('Manual Cache Clearing', 'comet-cache')."\n";
286
  echo ' </a>'."\n";
287
 
356
 
357
  echo '<div class="plugin-menu-page-panel'.(!IS_PRO && $this->plugin->isProPreview() ? ' pro-preview' : '').'">'."\n";
358
 
359
+ echo ' <a href="#" class="plugin-menu-page-panel-heading" data-additional-pro-features="'.(!IS_PRO && $this->plugin->isProPreview() ? __('additional pro features', 'comet-cache') : '').'">'."\n";
360
  echo ' <i class="si si-server"></i> '.__('Automatic Cache Clearing', 'comet-cache')."\n";
361
  echo ' </a>'."\n";
362
 
366
  echo ' <img src="'.esc_attr($this->plugin->url('/src/client-s/images/auto-clear-ss.png')).'" class="screenshot" />'."\n";
367
  echo ' <p>'.sprintf(__('This is built into the %1$s plugin; i.e., this functionality is "always on". If you edit a Post/Page (or delete one), %1$s will automatically clear the cache file(s) associated with that content. This way a new updated version of the cache will be created automatically the next time this content is accessed. Simple updates like this occur each time you make changes in the Dashboard, and %1$s will notify you of these as they occur. %1$s monitors changes to Posts (of any kind, including Pages), Categories, Tags, Links, Themes (even Users), and more.', 'comet-cache'), esc_html(NAME)).'</p>'."\n";
368
  if (IS_PRO || $this->plugin->isProPreview()) {
369
+ echo ' <div data-pro-version-only="'.(!IS_PRO ? __('pro version only', 'comet-cache') : '').'">'."\n";
370
  echo ' <p><select name="'.esc_attr(GLOBAL_NS).'[saveOptions][change_notifications_enable]" class="-no-if-enabled" style="width:auto;">'."\n";
371
+ echo ' <option value="1"'.selected($this->plugin->options['change_notifications_enable'], '1', false).'>'.sprintf(__('Yes, enable %1$s notifications in the Dashboard when cache files are cleared automatically.', 'comet-cache'), esc_html(NAME)).'</option>'."\n";
372
  echo ' <option value="0"'.selected($this->plugin->options['change_notifications_enable'], '0', false).'>'.sprintf(__('No, I don\'t want to know (don\'t really care) what %1$s is doing behind-the-scene.', 'comet-cache'), esc_html(NAME)).'</option>'."\n";
373
  echo ' </select></p>'."\n";
374
  echo ' </div>'."\n";
456
 
457
  if (IS_PRO || $this->plugin->isProPreview()) {
458
  echo ' <hr />'."\n";
459
+ echo ' <h3 data-pro-version-only="'.(!IS_PRO ? __('pro version only', 'comet-cache') : '').'">'.__('Misc. Auto-Clear Options', 'comet-cache').'</h3>'."\n";
460
  echo ' <h4 style="margin-bottom:0;">'.__('Auto-Clear a List of Custom URLs Too?', 'comet-cache').'</h4>'."\n";
461
  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";
462
  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";
471
  if (IS_PRO || $this->plugin->isProPreview()) {
472
  echo '<div class="plugin-menu-page-panel">'."\n";
473
 
474
+ echo ' <a href="#" class="plugin-menu-page-panel-heading" data-pro-version-only="'.(!IS_PRO ? __('pro version only', 'comet-cache') : '').'">'."\n";
475
  echo ' <i class="si si-pie-chart"></i> '.__('Cache-Related Statistics', 'comet-cache')."\n";
476
  echo ' </a>'."\n";
477
 
537
 
538
  echo '<div class="plugin-menu-page-panel'.(!IS_PRO && $this->plugin->isProPreview() ? ' pro-preview' : '').'">'."\n";
539
 
540
+ echo ' <a href="#" class="plugin-menu-page-panel-heading" data-additional-pro-features="'.(!IS_PRO && $this->plugin->isProPreview() ? __('additional pro features', 'comet-cache') : '').'">'."\n";
541
  echo ' <i class="si si-clock-o"></i> '.__('Cache Expiration Time', 'comet-cache')."\n";
542
  echo ' </a>'."\n";
543
 
566
  $_sys_getloadavg_unavailable = ($this->plugin->isProPreview() ? false : !$this->plugin->sysLoadAverages());
567
  echo ' <div>'."\n";
568
  echo ' <hr />'."\n";
569
+ echo ' <h3 data-pro-version-only="'.(!IS_PRO ? __('pro version only', 'comet-cache') : '').'" style="'.($_sys_getloadavg_unavailable ? 'opacity: 0.5;' : '').'">'.__('Disable Cache Expiration If Server Load Average is High?', 'comet-cache').'</h3>'."\n";
570
  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";
571
  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";
572
  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";
620
  if (IS_PRO || $this->plugin->isProPreview()) {
621
  echo '<div class="plugin-menu-page-panel'.(!IS_PRO ? ' pro-preview' : '').'">'."\n";
622
 
623
+ echo ' <a href="#" class="plugin-menu-page-panel-heading" data-pro-version-only="'.(!IS_PRO ? __('pro version only', 'comet-cache') : '').'">'."\n";
624
  echo ' <i class="si si-octi-organization"></i> '.__('Logged-In Users', 'comet-cache')."\n";
625
  echo ' </a>'."\n";
626
 
627
  echo ' <div class="plugin-menu-page-panel-body clearfix">'."\n";
628
  echo ' <i class="si si-group si-4x" style="float:right; margin: 0 0 0 25px;"></i>'."\n";
629
  echo ' <h3>'.__('Caching Enabled for Logged-In Users &amp; Comment Authors?', 'comet-cache').'</h3>'."\n";
630
+ echo ' <p>'.__('This should almost always be set to <code>No</code>. Most sites don\'t 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. In short, don\'t turn this on unless you know what you\'re doing. Note also that most sites get most (sometimes all) of their traffic from users who <em>are not</em> logged-in. When a user <em>is</em> logged-in, disabling the cache is generally a good idea because a logged-in user has a session open with your site. The content they view should remain very dynamic in this scenario.', 'comet-cache').'</p>'."\n";
631
  echo ' <i class="si si-sitemap si-4x" style="float:right; margin: 0 0 0 25px;"></i>'."\n";
632
+ 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 <em>are</em> logged-in, 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 (i.e., 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; i.e., it\'s not an issue in most cases. In other words, unless you\'re short on disk space, or you have thousands of users, the disk overhead is neglible.', 'comet-cache'), esc_html(NAME)).'</p>'."\n";
633
  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";
634
  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";
635
  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";
641
  if ($this->plugin->options['when_logged_in'] === '1' && $this->plugin->applyWpFilters(GLOBAL_NS.'_when_logged_in_no_admin_bar', true)) {
642
  echo '<p class="warning">'.sprintf(__('<strong>Warning:</strong> Whenever you enable caching for logged-in users (without a separate cache for each user), the WordPress Admin Bar <em>must</em> be disabled to prevent one user from seeing another user\'s details in the Admin Bar. <strong>Given your current configuration, %1$s will automatically hide the WordPress Admin Bar on the front-end of your site.</strong>', 'comet-cache'), esc_html(NAME)).'</p>'."\n";
643
  }
644
+ echo ' <p class="info">'.sprintf(__('<strong>Note:</strong> %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 comment threads 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 considered by the logged-in user check.', 'comet-cache'), esc_html(NAME)).'</p>'."\n";
645
+
646
  echo ' <hr />'."\n";
647
+
648
  echo ' <div class="plugin-menu-page-panel-if-enabled -logged-in-users-options">'."\n";
649
+ echo ' <h3>'.__('Cache Pages Containing Nonce Values in Markup?', 'comet-cache').'</h3>'."\n";
650
+ echo ' <p>'.sprintf(__('This should almost always be set to <code>Yes</code>. WordPress injects Nonces (<a href="https://cometcache.com/r/numbers-used-once-nonce/" target="_blank" rel="external">numbers used once</a>) into the markup on any given page that a logged-in user lands on. These Nonce values are generally used to improve security when actions are taken by a user; e.g., posting a form or clicking a link that performs an action. If you set this to <code>No</code>, any page containing an Nonce will bypass the cache and be served dynamically (a performance hit). Even the Admin Bar in WordPress injects Nonce values. That\'s reason enough to leave this at the default value of <code>Yes</code>; i.e., so Nonce values in the markup don\'t result in a cache bypass. In short, don\'t set this to <code>No</code> unless you know what you\'re doing.', 'comet-cache'), esc_html(NAME)).'</p>'."\n";
651
+ echo ' <p><select name="'.esc_attr(GLOBAL_NS).'[saveOptions][cache_nonce_values_when_logged_in]">'."\n";
652
+ echo ' <option value="1"'.selected($this->plugin->options['cache_nonce_values_when_logged_in'], '1', false).'>'.__('Yes, for logged-in users, intelligently cache pages containing Nonce values (recommended).', 'comet-cache').'</option>'."\n";
653
+ echo ' <option value="0"'.selected($this->plugin->options['cache_nonce_values_when_logged_in'], '0', false).'>'.__('No, for logged-in users, refuse to cache pages containing Nonce values.', 'comet-cache').'</option>'."\n";
654
+ echo ' </select></p>'."\n";
655
+ echo ' <p class="info">'.sprintf(__('<strong>Note:</strong> Nonce values in WordPress have a limited lifetime. They can expire just 12 hours after they were first generated. For this reason, %1$s will automatically force cache files containing Nonce values to expire once they are 12+ hours old; i.e., a new request for an expired page containing Nonce values will be rebuilt automatically, generating new Nonces that will continue to operate as expected. This rule is enforced no matter what your overall Cache Expiration Time is set to.', 'comet-cache'), esc_html(NAME)).'</p>'."\n";
656
+ echo ' <hr />'."\n";
657
  echo ' <h3>'.__('Static CDN Filters Enabled for Logged-In Users &amp; Comment Authors?', 'comet-cache').'</h3>'."\n";
658
+ 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 site owners. 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";
659
  echo ' <p><select name="'.esc_attr(GLOBAL_NS).'[saveOptions][cdn_when_logged_in]">'."\n";
660
  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";
661
  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";
662
  echo ' </select></p>'."\n";
663
  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";
664
  echo ' <hr />'."\n";
 
 
 
 
 
 
 
 
665
  echo ' <h3>'.__('Enable HTML Compression for Logged-In Users?', 'comet-cache').'</h3>'."\n";
666
  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";
667
  echo ' <p><select name="'.esc_attr(GLOBAL_NS).'[saveOptions][htmlc_when_logged_in]">'."\n";
675
  }
676
  /* ----------------------------------------------------------------------------------------- */
677
 
678
+ echo '<div class="plugin-menu-page-panel'.(!IS_PRO && $this->plugin->isProPreview() ? ' pro-preview' : '').'">'."\n";
679
 
680
+ echo ' <a href="#" class="plugin-menu-page-panel-heading" data-additional-pro-features="'.(!IS_PRO && $this->plugin->isProPreview() ? __('additional pro features', 'comet-cache') : '').'">'."\n";
681
  echo ' <i class="si si-question-circle"></i> '.__('GET Requests', 'comet-cache')."\n";
682
  echo ' </a>'."\n";
683
 
684
  echo ' <div class="plugin-menu-page-panel-body clearfix">'."\n";
685
+
686
  echo ' <i class="si si-question-circle si-4x" style="float:right; margin: 0 0 0 25px;"></i>'."\n";
687
  echo ' <h3>'.__('Caching Enabled for GET (Query String) Requests?', 'comet-cache').'</h3>'."\n";
688
+ echo ' <p>'.__('This should almost always be set to <code>No</code>. UNLESS, you\'re using unfriendly Permalinks; i.e., if all of your URLs contain a query string (like <code>?p=123</code>). In such a case, you should set this option to <code>Yes</code>. However, it\'s better to update your Permalink options and use friendly Permalinks, which also optimizes your site for search engines. Again, if you\'re using friendly Permalinks (recommended) you can leave this at the default value of <code>No</code>.', 'comet-cache').'</p>'."\n";
689
  echo ' <p><select name="'.esc_attr(GLOBAL_NS).'[saveOptions][get_requests]">'."\n";
690
  echo ' <option value="0"'.selected($this->plugin->options['get_requests'], '0', false).'>'.__('No, do NOT cache (or serve a cache file) when a query string is present.', 'comet-cache').'</option>'."\n";
691
  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";
692
  echo ' </select></p>'."\n";
693
+ echo ' <p class="info">'.sprintf(__('<strong>Advanced Tip:</strong> If you are not caching GET requests (recommended), but you <em>do</em> 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 <em>are</em> caching GET requests and you want to force %1$s to <em>not</em> 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";
694
+ echo ' <p style="font-style:italic;">'.__('<strong>Other Request Types:</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 automatically. 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";
695
+
696
+ if (IS_PRO || $this->plugin->isProPreview()) {
697
+ echo '<div>'."\n";
698
+ echo '<hr />'."\n";
699
+ echo '<h3 data-pro-version-only="'.(!IS_PRO ? __('pro version only', 'comet-cache') : '').'">'.__('List of GET Variable Names to Ignore', 'comet-cache').'</h3>'."\n";
700
+ echo '<p>'.__('You can enter one variable name per line. Each of the variable names that you list here will be ignored entirely; i.e., not considered when caching any given page, and not considered when serving any page that is already cached. For example, many sites use Google Analytics and there are <a href="https://cometcache.com/r/google-analytics-variables/" target="_blank" rel="external">GET request variables used by Google Analytics</a>, which are read by client-side JavaScript only. Those GET variables can be ignored altogether when it comes to the cache algorithm — speeding up your site even further.', 'comet-cache').'</p>'."\n";
701
+ echo '<p><textarea name="'.esc_attr(GLOBAL_NS).'[saveOptions][ignore_get_request_vars]" rows="5" spellcheck="false" class="monospace">'.format_to_edit($this->plugin->options['ignore_get_request_vars']).'</textarea></p>'."\n";
702
+ echo '<p style="font-style:italic;">'.__('A wildcard <code>*</code> character can also be used when necessary; e.g., <code>utm_*</code> (where <code>*</code> = 0 or more characters that are NOT a slash <code>/</code>). 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";
703
+ echo '</div>'."\n";
704
+ }
705
  echo ' </div>'."\n";
706
 
707
  echo '</div>'."\n";
733
  echo '<div class="plugin-menu-page-panel">'."\n";
734
 
735
  echo ' <a href="#" class="plugin-menu-page-panel-heading">'."\n";
736
+ echo ' <i class="si si-feed"></i> '.__('Feed Caching', 'comet-cache')."\n";
737
  echo ' </a>'."\n";
738
 
739
  echo ' <div class="plugin-menu-page-panel-body clearfix">'."\n";
755
  ((defined('SUBDOMAIN_INSTALL') && SUBDOMAIN_INSTALL) || $this->plugin->canConsiderDomainMapping());
756
 
757
  if ($this->plugin->applyWpFilters(GLOBAL_NS.'_exclude_hosts_option_enable', $exclude_hosts_option_enable)) {
 
 
758
  echo '<div class="plugin-menu-page-panel">'."\n";
759
 
760
  echo ' <a href="#" class="plugin-menu-page-panel-heading">'."\n";
761
+ echo ' <i class="si si-ban"></i> '.__('Host Exclusions', 'comet-cache')."\n";
762
  echo ' </a>'."\n";
763
 
764
  echo ' <div class="plugin-menu-page-panel-body clearfix">'."\n";
779
  echo '<div class="plugin-menu-page-panel">'."\n";
780
 
781
  echo ' <a href="#" class="plugin-menu-page-panel-heading">'."\n";
782
+ echo ' <i class="si si-ban"></i> '.__('URI Exclusions', 'comet-cache')."\n";
783
  echo ' </a>'."\n";
784
 
785
  echo ' <div class="plugin-menu-page-panel-body clearfix">'."\n";
801
  echo '<div class="plugin-menu-page-panel">'."\n";
802
 
803
  echo ' <a href="#" class="plugin-menu-page-panel-heading">'."\n";
804
+ echo ' <i class="si si-ban"></i> '.__('HTTP Referrer Exclusions', 'comet-cache')."\n";
805
  echo ' </a>'."\n";
806
 
807
  echo ' <div class="plugin-menu-page-panel-body clearfix">'."\n";
819
  echo '<div class="plugin-menu-page-panel">'."\n";
820
 
821
  echo ' <a href="#" class="plugin-menu-page-panel-heading">'."\n";
822
+ echo ' <i class="si si-ban"></i> '.__('User-Agent Exclusions', 'comet-cache')."\n";
823
  echo ' </a>'."\n";
824
 
825
  echo ' <div class="plugin-menu-page-panel-body clearfix">'."\n";
837
  if (IS_PRO || $this->plugin->isProPreview()) {
838
  echo '<div class="plugin-menu-page-panel'.(!IS_PRO ? ' pro-preview' : '').'">'."\n";
839
 
840
+ echo ' <a href="#" class="plugin-menu-page-panel-heading" data-pro-version-only="'.(!IS_PRO ? __('pro version only', 'comet-cache') : '').'">'."\n";
841
  echo ' <i class="si si-sitemap"></i> '.__('Auto-Cache Engine', 'comet-cache')."\n";
842
  echo ' </a>'."\n";
843
 
891
  if (IS_PRO || $this->plugin->isProPreview()) {
892
  echo '<div class="plugin-menu-page-panel'.(!IS_PRO ? ' pro-preview' : '').'">'."\n";
893
 
894
+ echo ' <a href="#" class="plugin-menu-page-panel-heading" data-pro-version-only="'.(!IS_PRO ? __('pro version only', 'comet-cache') : '').'">'."\n";
895
  echo ' <i class="si si-html5"></i> '.__('HTML Compression', 'comet-cache')."\n";
896
  echo ' </a>'."\n";
897
 
905
  echo ' <option value="0"'.(!IS_PRO ? '' : selected($this->plugin->options['htmlc_enable'], '0', false)).'>'.__('No, do NOT compress HTML/CSS/JS code at runtime.', 'comet-cache').'</option>'."\n";
906
  echo ' <option value="1"'.(!IS_PRO ? ' selected' : selected($this->plugin->options['htmlc_enable'], '1', false)).'>'.__('Yes, I want to compress HTML/CSS/JS for blazing fast speeds.', 'comet-cache').'</option>'."\n";
907
  echo ' </select></p>'."\n";
 
908
  echo ' <hr />'."\n";
909
  echo ' <div class="plugin-menu-page-panel-if-enabled -htmlc-options">'."\n";
910
  echo ' <h3>'.__('HTML Compression Options', 'comet-cache').'</h3>'."\n";
970
  if (IS_PRO || $this->plugin->isProPreview()) {
971
  echo '<div class="plugin-menu-page-panel'.(!IS_PRO ? ' pro-preview' : '').'">'."\n";
972
 
973
+ echo ' <a href="#" class="plugin-menu-page-panel-heading" data-pro-version-only="'.(!IS_PRO ? __('pro version only', 'comet-cache') : '').'">'."\n";
974
  echo ' <i class="si si-cloud"></i> '.__('Static CDN Filters', 'comet-cache')."\n";
975
  echo ' </a>'."\n";
976
 
977
  echo ' <div class="plugin-menu-page-panel-body clearfix">'."\n";
978
+ echo ' <button type="button" class="plugin-menu-page-clear-cdn-cache" style="float:right; margin:0 0 1em 1em;" title="'.esc_attr(__('Clear CDN Cache (Bump CDN Invalidation Counter)', 'comet-cache')).'">'.__('Clear CDN Cache', 'comet-cache').' <img src="'.esc_attr($this->plugin->url('/src/client-s/images/clear.png')).'" style="width:16px; height:16px; display:inline-block;" /></button>'."\n";
979
  echo ' <h3>'.__('Enable Static CDN Filters (e.g., MaxCDN/CloudFront)?', 'comet-cache').'</h3>'."\n";
980
  echo ' <p>'.sprintf(__('This feature allows you to serve some and/or ALL static files on your site from a CDN of your choosing. This is made possible through content/URL filters exposed by WordPress and implemented by %1$s. All it requires is that you setup a CDN host name sourced by your WordPress installation domain. You enter that CDN host name below and %1$s will do the rest! Super easy, and it doesn\'t require any DNS changes either. :-) Please <a href="http://cometcache.com/r/static-cdn-filters-general-instructions/" target="_blank">click here</a> for a general set of instructions.', 'comet-cache'), esc_html(NAME)).'</p>'."\n";
981
  echo ' <p>'.__('<strong>What\'s a CDN?</strong> It\'s a Content Delivery Network (i.e., a network of optimized servers) designed to cache static resources served from your site (e.g., JS/CSS/images and other static files) onto it\'s own servers, which are located strategically in various geographic areas around the world. Integrating a CDN for static files can dramatically improve the speed and performance of your site, lower the burden on your own server, and reduce latency associated with visitors attempting to access your site from geographic areas of the world that might be very far away from the primary location of your own web servers.', 'comet-cache').'</p>'."\n";
1072
  if ($is_apache || $this->plugin->isProPreview()) {
1073
  echo '<div class="plugin-menu-page-panel'.(!IS_PRO && $this->plugin->isProPreview() ? ' pro-preview' : '').'">'."\n";
1074
 
1075
+ echo ' <a href="#" class="plugin-menu-page-panel-heading" data-additional-pro-features="'.(!IS_PRO && $this->plugin->isProPreview() ? __('additional pro features', 'comet-cache') : '').'">'."\n";
1076
  echo ' <i class="si si-server"></i> '.__('Apache Optimizations', 'comet-cache')."\n";
1077
  echo ' </a>'."\n";
1078
 
1105
 
1106
  if (IS_PRO || $this->plugin->isProPreview()) {
1107
  echo ' <hr />'."\n";
1108
+ echo ' <h3 data-pro-version-only="'.(!IS_PRO ? __('pro version only', 'comet-cache') : '').'">'.__('Leverage Browser Caching?', 'comet-cache').'</h3>'."\n";
1109
  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";
1110
  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 visitor\'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";
1111
  echo ' <p><select name="'.esc_attr(GLOBAL_NS).'[saveOptions][htaccess_browser_caching_enable]" data-target=".-htaccess-browser-caching-enable-options">'."\n";
1121
 
1122
  if ((IS_PRO && !empty($GLOBALS['wp_rewrite']->permalink_structure)) || $this->plugin->isProPreview()) {
1123
  echo ' <hr />'."\n";
1124
+ echo ' <h3 data-pro-version-only="'.(!IS_PRO ? __('pro version only', 'comet-cache') : '').'">'.__('Enforce Canonical URLs?', 'comet-cache').'</h3>'."\n";
1125
  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";
1126
  echo ' <p><select name="'.esc_attr(GLOBAL_NS).'[saveOptions][htaccess_enforce_canonical_urls]" data-target=".-htaccess-enforce-canonical-urls-options">'."\n";
1127
  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";
1140
 
1141
  if ((IS_PRO && $this->plugin->options['cdn_enable']) || $this->plugin->isProPreview()) {
1142
  echo ' <hr />'."\n";
1143
+ echo ' <h3 data-pro-version-only="'.(!IS_PRO ? __('pro version only', 'comet-cache') : '').'">'.__('Send Access-Control-Allow-Origin Header?', 'comet-cache').'</h3>'."\n";
1144
  if ($this->plugin->options['cdn_enable'] && !$this->plugin->options['htaccess_access_control_allow_origin']) {
1145
  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";
1146
  }
1164
  if (IS_PRO || $this->plugin->isProPreview()) {
1165
  echo '<div class="plugin-menu-page-panel'.(!IS_PRO ? ' pro-preview' : '').'">'."\n";
1166
 
1167
+ echo ' <a href="#" class="plugin-menu-page-panel-heading" data-pro-version-only="'.(!IS_PRO ? __('pro version only', 'comet-cache') : '').'">'."\n";
1168
  echo ' <i class="si si-octi-versions"></i> '.__('Dynamic Version Salt', 'comet-cache')."\n";
1169
  echo ' </a>'."\n";
1170
 
1174
  echo ' <p>'.sprintf(__('<em>Note: Understanding the %1$s <a href="http://cometcache.com/r/kb-branched-cache-structure/" target="_blank">Branched Cache Structure</a> is a prerequisite to understanding how Dynamic Version Salts are added to the mix.</em>', 'comet-cache'), esc_html(NAME)).'</p>'."\n";
1175
  echo ' <p>'.__('A Version Salt gives you the ability to dynamically create multiple variations of the cache, and those dynamic variations will be served on subsequent visits; e.g., if a visitor has a specific cookie (of a certain value) they will see pages which were cached with that version (i.e., w/ that Version Salt: the value of the cookie). A Version Salt can really be anything.', 'comet-cache').'</p>'."\n";
1176
  echo ' <p>'.__('A Version Salt can be a single variable like <code>$_COOKIE[\'my_cookie\']</code>, or it can be a combination of multiple variables, like <code>$_COOKIE[\'my_cookie\'].$_COOKIE[\'my_other_cookie\']</code>. (When using multiple variables, please separate them with a dot, as shown in the example.)', 'comet-cache').'</p>'."\n";
1177
+ echo ' <p>'.__('Experts could even use PHP ternary expressions that evaluate into something. For example: <code>((preg_match(\'/iPhone/i\', $_SERVER[\'HTTP_USER_AGENT\'])) ? \'iPhones\' : \'\')</code>. This would force a separate version of the cache to be created for iPhones (e.g., <code>PROTOCOL.HOST.URI[...]v/iPhones.html</code>).', 'comet-cache').'</p>'."\n";
1178
  echo ' <p>'.__('For more documentation, please see <a href="http://cometcache.com/r/kb-dynamic-version-salts/" target="_blank">Dynamic Version Salts</a>.', 'comet-cache').'</p>'."\n";
1179
  echo ' <hr />'."\n";
1180
  echo ' <h3>'.sprintf(__('Create a Dynamic Version Salt For %1$s? &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-size:90%%; opacity:0.5;">150%% OPTIONAL</span>', 'comet-cache'), esc_html(NAME)).'</h3>'."\n";
1181
+ echo ' <table style="width:100%;"><tr><td style="width:1px; font-weight:bold; white-space:nowrap;">PROTOCOL.HOST.URI.v.</td><td><input type="text" name="'.esc_attr(GLOBAL_NS).'[saveOptions][version_salt]" value="'.esc_attr($this->plugin->options['version_salt']).'" class="monospace" placeholder="$_COOKIE[\'my_cookie\']" /></td><td style="width:1px; font-weight:bold; white-space:nowrap;"></td></tr></table>'."\n";
1182
  echo ' <p class="info" style="display:block;">'.__('<a href="http://php.net/manual/en/language.variables.superglobals.php" target="_blank">Super Globals</a> work here; <a href="http://codex.wordpress.org/Editing_wp-config.php#table_prefix" target="_blank"><code>$GLOBALS[\'table_prefix\']</code></a> is a popular one.<br />Or, perhaps a PHP Constant defined in <code>/wp-config.php</code>; such as <code>WPLANG</code> or <code>DB_HOST</code>.', 'comet-cache').'</p>'."\n";
1183
  echo ' <p class="notice" style="display:block;">'.__('<strong>Important:</strong> your Version Salt is scanned for PHP syntax errors via <a href="http://phpcodechecker.com/" target="_blank"><code>phpCodeChecker.com</code></a>. If errors are found, you\'ll receive a notice in the Dashboard.', 'comet-cache').'</p>'."\n";
1184
  echo ' <p class="info" style="display:block;">'.__('If you\'ve enabled a separate cache for each user (optional) that\'s perfectly OK. A Version Salt works with user caching too.', 'comet-cache').'</p>'."\n";
1211
  if (IS_PRO || $this->plugin->isProPreview()) {
1212
  echo '<div class="plugin-menu-page-panel'.(!IS_PRO ? ' pro-preview' : '').'">'."\n";
1213
 
1214
+ echo ' <a href="#" class="plugin-menu-page-panel-heading" data-pro-version-only="'.(!IS_PRO ? __('pro version only', 'comet-cache') : '').'">'."\n";
1215
  echo ' <i class="si si-arrow-circle-o-up"></i> '.__('Import/Export Options', 'comet-cache')."\n";
1216
  echo ' </a>'."\n";
1217
 
1224
  echo ' <h3>'.sprintf(__('Export Existing Options from this %1$s Installation?', 'comet-cache'), esc_html(NAME)).'</h3>'."\n";
1225
  echo ' <button type="button" class="plugin-menu-page-export-options" style="float:right; margin: 0 0 0 25px;"'.// Exports existing options from this installation.
1226
  ' data-action="'.esc_attr(add_query_arg(urlencode_deep(['page' => GLOBAL_NS, '_wpnonce' => wp_create_nonce(), GLOBAL_NS => ['exportOptions' => '1']]), self_admin_url('/admin.php'))).'">'.
1227
+ ' '.__('options.json', 'comet-cache').' <i class="si si-arrow-circle-o-down"></i></button>'."\n";
1228
  echo ' <p>'.sprintf(__('Download your existing options and import them all into another %1$s installation; saves time on future installs.', 'comet-cache'), esc_html(NAME)).'</p>'."\n";
1229
  echo ' </div>'."\n";
1230
 
src/includes/classes/Notes.php ADDED
@@ -0,0 +1,127 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace WebSharks\CometCache\Classes;
3
+
4
+ use WebSharks\CometCache\Traits;
5
+
6
+ /**
7
+ * Notes.
8
+ *
9
+ * @since 161119 Notes.
10
+ */
11
+ class Notes extends AbsBase
12
+ {
13
+ use Traits\Shared\StringUtils;
14
+
15
+ /**
16
+ * @since 161119
17
+ *
18
+ * @var array
19
+ */
20
+ protected $notes;
21
+
22
+ /**
23
+ * Class constructor.
24
+ *
25
+ * @since 161119 Notes.
26
+ */
27
+ public function __construct()
28
+ {
29
+ parent::__construct();
30
+
31
+ $this->notes = [];
32
+ }
33
+
34
+ /**
35
+ * Get notes.
36
+ *
37
+ * @since 161119 Notes.
38
+ *
39
+ * @return array Notes.
40
+ */
41
+ public function notes()
42
+ {
43
+ return $this->notes;
44
+ }
45
+
46
+ /**
47
+ * Add note.
48
+ *
49
+ * @param string $key Key.
50
+ * @param string $note Note.
51
+ *
52
+ * @since 161119 Notes.
53
+ */
54
+ public function add($key, $note)
55
+ {
56
+ $this->notes[$key] = $note;
57
+ }
58
+
59
+ /**
60
+ * Add line break.
61
+ *
62
+ * @since 161119 Notes.
63
+ */
64
+ public function addLineBreak()
65
+ {
66
+ $this->notes[] = "\n";
67
+ }
68
+
69
+ /**
70
+ * Add divider.
71
+ *
72
+ * @since 161119 Notes.
73
+ */
74
+ public function addDivider()
75
+ {
76
+ $this->notes[] = str_repeat('.', 70);
77
+ }
78
+
79
+ /**
80
+ * Add ASCII artwork.
81
+ *
82
+ * @param string $note Note.
83
+ *
84
+ * @since 161119 Notes.
85
+ */
86
+ public function addAsciiArt($note)
87
+ {
88
+ $this->notes[] = '*´¨)
89
+ ¸.•´¸.•*´¨) ¸.•*¨)
90
+ (¸.•´ (¸.•` ¤ '.$note.' ¤ ´¨)';
91
+ }
92
+
93
+ /**
94
+ * As HTML comments.
95
+ *
96
+ * @since 161119 HTML comments.
97
+ */
98
+ public function asHtmlComments()
99
+ {
100
+ $html_comments = ''; // Initialize.
101
+ $longest_key_size = 0; // Initialize.
102
+
103
+ foreach ($this->notes as $_key => $_note) {
104
+ if (is_string($_key) && $_key && isset($_note[0])) {
105
+ $longest_key_size = max($longest_key_size, mb_strlen($_key.':'));
106
+ }
107
+ } // unset($_key, $_note); // Housekeeping.
108
+
109
+ foreach ($this->notes as $_key => $_note) {
110
+ if (is_integer($_key)) {
111
+ if ($_note === "\n") {
112
+ $html_comments .= "\n";
113
+ } elseif (isset($_note[0])) {
114
+ $html_comments .= '<!-- '.htmlspecialchars($_note).' -->'."\n";
115
+ }
116
+ } elseif ($_key && !isset($_note[0])) {
117
+ $html_comments .= '<!-- '.htmlspecialchars($_key).' -->'."\n";
118
+ } elseif (!$_key && isset($_note[0])) {
119
+ $html_comments .= '<!-- '.htmlspecialchars($_note).' -->'."\n";
120
+ } elseif ($_key && isset($_note[0])) {
121
+ $html_comments .= '<!-- '.htmlspecialchars($this->strPad($_key.':', $longest_key_size).' '.$_note).' -->'."\n";
122
+ }
123
+ } // unset($_key, $_note); // Housekeeping.
124
+
125
+ return trim($html_comments);
126
+ }
127
+ }
src/includes/classes/Plugin.php CHANGED
@@ -147,7 +147,7 @@ class Plugin extends AbsBaseAp
147
  parent::__construct();
148
 
149
  /* -------------------------------------------------------------- */
150
- if (!($this->enable_hooks = (boolean) $enable_hooks)) {
151
  return; // Stop here; construct without hooks.
152
  }
153
  /* -------------------------------------------------------------- */
@@ -190,8 +190,10 @@ class Plugin extends AbsBaseAp
190
  'cache_clear_eval_code',
191
  'cache_clear_urls',
192
 
 
 
 
193
  'when_logged_in',
194
- 'when_logged_in_admin_bar',
195
 
196
  'version_salt',
197
 
@@ -317,10 +319,11 @@ class Plugin extends AbsBaseAp
317
  'allow_client_side_cache' => '0', // `0|1`.
318
  'when_logged_in' => '0', // `0|1|postload`.
319
  'get_requests' => '0', // `0|1`.
 
320
  'feeds_enable' => '0', // `0|1`.
321
  'cache_404_requests' => '0', // `0|1`.
322
  'cache_nonce_values' => '0', // `0|1`.
323
- 'cache_nonce_values_when_logged_in' => '0', // `0|1`.
324
 
325
  /* Related to exclusions. */
326
 
@@ -336,8 +339,11 @@ class Plugin extends AbsBaseAp
336
 
337
  /* Related to HTML compressor. */
338
 
339
- 'htmlc_enable' => '0', // Enable HTML compression?
340
- 'htmlc_css_exclusions' => '', // Empty string or line-delimited patterns.
 
 
 
341
  'htmlc_js_exclusions' => '.php?', // Empty string or line-delimited patterns.
342
  'htmlc_uri_exclusions' => '', // Empty string or line-delimited patterns.
343
  'htmlc_cache_expiration_time' => '14 days', // `strtotime()` compatible.
@@ -352,9 +358,6 @@ class Plugin extends AbsBaseAp
352
  'htmlc_compress_html_code' => '1', // `0|1`.
353
  'htmlc_when_logged_in' => '0', // `0|1`; enable when logged in?
354
 
355
- /* Related to Logged-In User Caching */
356
- 'when_logged_in_admin_bar' => '1', // `0|1`; enable when logged in?
357
-
358
  /* Related to auto-cache engine. */
359
 
360
  'auto_cache_enable' => '0', // `0|1`.
@@ -459,18 +462,15 @@ class Plugin extends AbsBaseAp
459
 
460
 
461
 
462
-
463
  add_action('admin_bar_menu', [$this, 'adminBarMenu']);
464
  add_action('wp_head', [$this, 'adminBarMetaTags'], 0);
465
  add_action('wp_enqueue_scripts', [$this, 'adminBarStyles']);
466
  add_action('wp_enqueue_scripts', [$this, 'adminBarScripts']);
467
 
468
-
469
  add_action('admin_head', [$this, 'adminBarMetaTags'], 0);
470
  add_action('admin_enqueue_scripts', [$this, 'adminBarStyles']);
471
  add_action('admin_enqueue_scripts', [$this, 'adminBarScripts']);
472
 
473
-
474
  add_action('admin_enqueue_scripts', [$this, 'enqueueAdminStyles']);
475
  add_action('admin_enqueue_scripts', [$this, 'enqueueAdminScripts']);
476
 
@@ -502,6 +502,7 @@ class Plugin extends AbsBaseAp
502
  add_action('pre_post_update', [$this, 'autoClearPostCacheTransition'], 10, 2);
503
 
504
  add_action('woocommerce_product_set_stock', [$this, 'autoClearPostCacheOnWooCommerceSetStock'], 10, 1);
 
505
  add_action('update_option_comment_mail_options', [$this, 'autoClearCache']);
506
 
507
  add_action('added_term_relationship', [$this, 'autoClearPostTermsCache'], 10, 1);
@@ -527,11 +528,7 @@ class Plugin extends AbsBaseAp
527
  return 'disabled-by-'.SLUG_TD; // MUST return a string literal that is not 'true' or '' (an empty string). See <http://bit.ly/1YItpdE>
528
  }); // See also why the Akismet nonce should be disabled: <http://jas.xyz/1R23f5c>
529
  }
530
-
531
 
532
-
533
-
534
-
535
 
536
  /* -------------------------------------------------------------- */
537
 
147
  parent::__construct();
148
 
149
  /* -------------------------------------------------------------- */
150
+ if (!($this->enable_hooks = (bool) $enable_hooks)) {
151
  return; // Stop here; construct without hooks.
152
  }
153
  /* -------------------------------------------------------------- */
190
  'cache_clear_eval_code',
191
  'cache_clear_urls',
192
 
193
+ 'ignore_get_request_vars',
194
+ 'cache_nonce_values_when_logged_in',
195
+
196
  'when_logged_in',
 
197
 
198
  'version_salt',
199
 
319
  'allow_client_side_cache' => '0', // `0|1`.
320
  'when_logged_in' => '0', // `0|1|postload`.
321
  'get_requests' => '0', // `0|1`.
322
+ 'ignore_get_request_vars' => 'utm_*', // Empty string or line-delimited patterns.
323
  'feeds_enable' => '0', // `0|1`.
324
  'cache_404_requests' => '0', // `0|1`.
325
  'cache_nonce_values' => '0', // `0|1`.
326
+ 'cache_nonce_values_when_logged_in' => '1', // `0|1`.
327
 
328
  /* Related to exclusions. */
329
 
339
 
340
  /* Related to HTML compressor. */
341
 
342
+ 'htmlc_enable' => '0', // Enable HTML compression?
343
+
344
+ 'htmlc_css_exclusions' => "id='rs-plugin-settings-inline-css'", // Empty string or line-delimited patterns.
345
+ // This defaults to an exclusion rule that handles compatibility with RevSlider. See: <https://github.com/websharks/comet-cache/issues/614>
346
+
347
  'htmlc_js_exclusions' => '.php?', // Empty string or line-delimited patterns.
348
  'htmlc_uri_exclusions' => '', // Empty string or line-delimited patterns.
349
  'htmlc_cache_expiration_time' => '14 days', // `strtotime()` compatible.
358
  'htmlc_compress_html_code' => '1', // `0|1`.
359
  'htmlc_when_logged_in' => '0', // `0|1`; enable when logged in?
360
 
 
 
 
361
  /* Related to auto-cache engine. */
362
 
363
  'auto_cache_enable' => '0', // `0|1`.
462
 
463
 
464
 
 
465
  add_action('admin_bar_menu', [$this, 'adminBarMenu']);
466
  add_action('wp_head', [$this, 'adminBarMetaTags'], 0);
467
  add_action('wp_enqueue_scripts', [$this, 'adminBarStyles']);
468
  add_action('wp_enqueue_scripts', [$this, 'adminBarScripts']);
469
 
 
470
  add_action('admin_head', [$this, 'adminBarMetaTags'], 0);
471
  add_action('admin_enqueue_scripts', [$this, 'adminBarStyles']);
472
  add_action('admin_enqueue_scripts', [$this, 'adminBarScripts']);
473
 
 
474
  add_action('admin_enqueue_scripts', [$this, 'enqueueAdminStyles']);
475
  add_action('admin_enqueue_scripts', [$this, 'enqueueAdminScripts']);
476
 
502
  add_action('pre_post_update', [$this, 'autoClearPostCacheTransition'], 10, 2);
503
 
504
  add_action('woocommerce_product_set_stock', [$this, 'autoClearPostCacheOnWooCommerceSetStock'], 10, 1);
505
+ add_action('woocommerce_product_set_stock_status', [$this, 'autoClearPostCacheOnWooCommerceSetStockStatus'], 10, 1);
506
  add_action('update_option_comment_mail_options', [$this, 'autoClearCache']);
507
 
508
  add_action('added_term_relationship', [$this, 'autoClearPostTermsCache'], 10, 1);
528
  return 'disabled-by-'.SLUG_TD; // MUST return a string literal that is not 'true' or '' (an empty string). See <http://bit.ly/1YItpdE>
529
  }); // See also why the Akismet nonce should be disabled: <http://jas.xyz/1R23f5c>
530
  }
 
531
 
 
 
 
532
 
533
  /* -------------------------------------------------------------- */
534
 
src/includes/classes/VsUpgrades.php CHANGED
@@ -9,7 +9,7 @@ namespace WebSharks\CometCache\Classes;
9
  class VsUpgrades extends AbsBase
10
  {
11
  /**
12
- * @type string Version they are upgrading from.
13
  *
14
  * @since 150422 Rewrite.
15
  */
@@ -44,6 +44,7 @@ class VsUpgrades extends AbsBase
44
  $this->fromLte160227();
45
  $this->fromLte160521();
46
  $this->fromLte160709();
 
47
  }
48
 
49
  /**
@@ -66,7 +67,7 @@ class VsUpgrades extends AbsBase
66
  delete_option(GLOBAL_NS.'_options');
67
  delete_option(GLOBAL_NS.'_apc_warning_bypass');
68
 
69
- if ((integer) $_child_blog['blog_id'] !== (integer) $current_site->blog_id) {
70
  wp_clear_scheduled_hook('_cron_'.GLOBAL_NS.'_auto_cache');
71
  wp_clear_scheduled_hook('_cron_'.GLOBAL_NS.'_cleanup');
72
  }
@@ -272,4 +273,26 @@ class VsUpgrades extends AbsBase
272
  $this->plugin->dismissMainNotice('new-pro-version-available'); // Dismiss any existing notices like this; upgrade notices are handled by WordPress now.
273
  }
274
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
275
  }
9
  class VsUpgrades extends AbsBase
10
  {
11
  /**
12
+ * @var string Version they are upgrading from.
13
  *
14
  * @since 150422 Rewrite.
15
  */
44
  $this->fromLte160227();
45
  $this->fromLte160521();
46
  $this->fromLte160709();
47
+ $this->fromLte161108();
48
  }
49
 
50
  /**
67
  delete_option(GLOBAL_NS.'_options');
68
  delete_option(GLOBAL_NS.'_apc_warning_bypass');
69
 
70
+ if ((int) $_child_blog['blog_id'] !== (int) $current_site->blog_id) {
71
  wp_clear_scheduled_hook('_cron_'.GLOBAL_NS.'_auto_cache');
72
  wp_clear_scheduled_hook('_cron_'.GLOBAL_NS.'_cleanup');
73
  }
273
  $this->plugin->dismissMainNotice('new-pro-version-available'); // Dismiss any existing notices like this; upgrade notices are handled by WordPress now.
274
  }
275
  }
276
+
277
+ /**
278
+ * @since 161108 When we enhanced built-in CSS exclusions.
279
+ * @since 161108 Start caching `nonce` values for logged-in users.
280
+ */
281
+ protected function fromLte161108()
282
+ {
283
+ if (version_compare($this->prev_version, '161108', '<=')) {
284
+ if (is_array($existing_options = get_site_option(GLOBAL_NS.'_options'))) {
285
+ if (IS_PRO && isset($existing_options['htmlc_css_exclusions']) && empty($existing_options['htmlc_css_exclusions'])) {
286
+ $this->plugin->options['htmlc_css_exclusions'] = $this->plugin->default_options['htmlc_css_exclusions'];
287
+ }
288
+ if (IS_PRO) { // Start caching `nonce` values for logged-in users.
289
+ $this->plugin->options['cache_nonce_values_when_logged_in'] = $this->plugin->default_options['cache_nonce_values_when_logged_in'];
290
+ }
291
+ if ($this->plugin->options !== $existing_options) {
292
+ $this->plugin->updateOptions($this->plugin->options, false);
293
+ $this->plugin->activate();
294
+ }
295
+ }
296
+ }
297
+ }
298
  }
src/includes/stub.php CHANGED
@@ -13,7 +13,7 @@ if (!defined('WPINC')) {
13
  require_once dirname(__DIR__).'/vendor/autoload.php';
14
  require_once __DIR__.'/functions/i18n-utils.php';
15
 
16
- ${__FILE__}['version'] = '160917'; //version//
17
  ${__FILE__}['plugin'] = dirname(dirname(__DIR__));
18
  ${__FILE__}['plugin'] .= '/'.basename(${__FILE__}['plugin']).'.php';
19
  ${__FILE__}['ns_path'] = str_replace('\\', '/', __NAMESPACE__); // To dir/path.
13
  require_once dirname(__DIR__).'/vendor/autoload.php';
14
  require_once __DIR__.'/functions/i18n-utils.php';
15
 
16
+ ${__FILE__}['version'] = '161119'; //version//
17
  ${__FILE__}['plugin'] = dirname(dirname(__DIR__));
18
  ${__FILE__}['plugin'] .= '/'.basename(${__FILE__}['plugin']).'.php';
19
  ${__FILE__}['ns_path'] = str_replace('\\', '/', __NAMESPACE__); // To dir/path.
src/includes/templates/advanced-cache.x-php CHANGED
@@ -12,7 +12,7 @@ if (!defined('WPINC')) {
12
  exit('Do NOT access this file directly: '.basename(__FILE__));
13
  }
14
  if (!defined('COMET_CACHE_PLUGIN_FILE')) {
15
- /**
16
  * Plugin file path.
17
  *
18
  * @since 140725 Reorganizing class members.
@@ -23,14 +23,14 @@ if (!defined('COMET_CACHE_PLUGIN_FILE')) {
23
  }
24
  if (defined('WP_DEBUG') && WP_DEBUG) {
25
  if ((include_once(dirname(COMET_CACHE_PLUGIN_FILE).'/src/includes/stub.php')) === false) {
26
- return; // Unable to find stub. Fail softly w/ PHP warning.
27
  }
28
  } elseif ((@include_once(dirname(COMET_CACHE_PLUGIN_FILE).'/src/includes/stub.php')) === false) {
29
  return; // Unable to find stub. Fail softly.
30
  }
31
  if (defined('WP_DEBUG') && WP_DEBUG) {
32
- if ((@include_once(dirname(COMET_CACHE_PLUGIN_FILE).'/src/includes/functions/wp-cache-postload.php')) === false) {
33
- return; // Unable to find postload function(s). Fail softly w/ PHP warning.
34
  }
35
  } elseif ((@include_once(dirname(COMET_CACHE_PLUGIN_FILE).'/src/includes/functions/wp-cache-postload.php')) === false) {
36
  return; // Unable to find postload function(s). Fail softly.
@@ -40,7 +40,7 @@ Classes\AdvCacheBackCompat::zcRequestVars();
40
  Classes\AdvCacheBackCompat::browserCacheConstant();
41
 
42
  if (!defined('COMET_CACHE_PRO')) {
43
- /**
44
  * Comet Cache Pro flag.
45
  *
46
  * @since 140422 First documented version.
@@ -50,7 +50,7 @@ if (!defined('COMET_CACHE_PRO')) {
50
  define('COMET_CACHE_PRO', IS_PRO);
51
  }
52
  if (!defined('COMET_CACHE_ENABLE')) {
53
- /**
54
  * Is Comet Cache enabled?
55
  *
56
  * @since 140422 First documented version.
@@ -60,7 +60,7 @@ if (!defined('COMET_CACHE_ENABLE')) {
60
  define('COMET_CACHE_ENABLE', '%%COMET_CACHE_ENABLE%%');
61
  }
62
  if (!defined('COMET_CACHE_DEBUGGING_ENABLE')) {
63
- /**
64
  * Is Comet Cache debugging enabled?
65
  *
66
  * @since 140422 First documented version.
@@ -70,7 +70,7 @@ if (!defined('COMET_CACHE_DEBUGGING_ENABLE')) {
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
  *
76
  * @since 140422 First documented version.
@@ -83,7 +83,7 @@ if (!defined('COMET_CACHE_ALLOW_CLIENT_SIDE_CACHE')) {
83
  define('COMET_CACHE_ALLOW_CLIENT_SIDE_CACHE', '%%COMET_CACHE_ALLOW_CLIENT_SIDE_CACHE%%');
84
  }
85
  if (!defined('COMET_CACHE_GET_REQUESTS')) {
86
- /**
87
  * Cache `$_GET` requests w/ a query string?
88
  *
89
  * @since 140422 First documented version.
@@ -92,8 +92,18 @@ if (!defined('COMET_CACHE_GET_REQUESTS')) {
92
  */
93
  define('COMET_CACHE_GET_REQUESTS', '%%COMET_CACHE_GET_REQUESTS%%');
94
  }
 
 
 
 
 
 
 
 
 
 
95
  if (!defined('COMET_CACHE_CACHE_404_REQUESTS')) {
96
- /**
97
  * Cache 404 errors?
98
  *
99
  * @since 140422 First documented version.
@@ -103,7 +113,7 @@ if (!defined('COMET_CACHE_CACHE_404_REQUESTS')) {
103
  define('COMET_CACHE_CACHE_404_REQUESTS', '%%COMET_CACHE_CACHE_404_REQUESTS%%');
104
  }
105
  if (!defined('COMET_CACHE_CACHE_NONCE_VALUES')) {
106
- /**
107
  * Cache HTML containing nonce values?
108
  *
109
  * @since 160103 First documented version.
@@ -113,7 +123,7 @@ if (!defined('COMET_CACHE_CACHE_NONCE_VALUES')) {
113
  define('COMET_CACHE_CACHE_NONCE_VALUES', '%%COMET_CACHE_CACHE_NONCE_VALUES%%');
114
  }
115
  if (!defined('COMET_CACHE_CACHE_NONCE_VALUES_WHEN_LOGGED_IN')) {
116
- /**
117
  * Cache HTML containing nonce values for Logged-In Users?
118
  *
119
  * @since 160103 First documented version.
@@ -123,7 +133,7 @@ if (!defined('COMET_CACHE_CACHE_NONCE_VALUES_WHEN_LOGGED_IN')) {
123
  define('COMET_CACHE_CACHE_NONCE_VALUES_WHEN_LOGGED_IN', '%%COMET_CACHE_CACHE_NONCE_VALUES_WHEN_LOGGED_IN%%');
124
  }
125
  if (!defined('COMET_CACHE_FEEDS_ENABLE')) {
126
- /**
127
  * Cache XML/RSS/Atom feeds?
128
  *
129
  * @since 140422 First documented version.
@@ -134,7 +144,7 @@ if (!defined('COMET_CACHE_FEEDS_ENABLE')) {
134
  }
135
 
136
  if (!defined('COMET_CACHE_DIR')) {
137
- /**
138
  * Directory used to store cache files; relative to `WP_CONTENT_DIR`.
139
  *
140
  * @since 140422 First documented version.
@@ -144,7 +154,7 @@ if (!defined('COMET_CACHE_DIR')) {
144
  define('COMET_CACHE_DIR', WP_CONTENT_DIR.'/'.'%%COMET_CACHE_DIR%%');
145
  }
146
  if (!defined('COMET_CACHE_MAX_AGE')) {
147
- /**
148
  * Cache expiration time.
149
  *
150
  * @since 140422 First documented version.
@@ -155,7 +165,7 @@ if (!defined('COMET_CACHE_MAX_AGE')) {
155
  }
156
 
157
  if (!defined('COMET_CACHE_EXCLUDE_HOSTS')) {
158
- /**
159
  * Host exclusions.
160
  *
161
  * @since 160706 Adding host exclusions.
@@ -165,7 +175,7 @@ if (!defined('COMET_CACHE_EXCLUDE_HOSTS')) {
165
  define('COMET_CACHE_EXCLUDE_HOSTS', '%%COMET_CACHE_EXCLUDE_HOSTS%%');
166
  }
167
  if (!defined('COMET_CACHE_EXCLUDE_URIS')) {
168
- /**
169
  * URI exclusions.
170
  *
171
  * @since 140422 First documented version.
@@ -175,7 +185,7 @@ if (!defined('COMET_CACHE_EXCLUDE_URIS')) {
175
  define('COMET_CACHE_EXCLUDE_URIS', '%%COMET_CACHE_EXCLUDE_URIS%%');
176
  }
177
  if (!defined('COMET_CACHE_EXCLUDE_CLIENT_SIDE_URIS')) {
178
- /**
179
  * Client-side URI exclusions.
180
  *
181
  * @since 151220 Adding support for client-side URI exclusions.
@@ -185,7 +195,7 @@ if (!defined('COMET_CACHE_EXCLUDE_CLIENT_SIDE_URIS')) {
185
  define('COMET_CACHE_EXCLUDE_CLIENT_SIDE_URIS', '%%COMET_CACHE_EXCLUDE_CLIENT_SIDE_URIS%%');
186
  }
187
  if (!defined('COMET_CACHE_EXCLUDE_REFS')) {
188
- /**
189
  * HTTP referrer exclusions.
190
  *
191
  * @since 140422 First documented version.
@@ -195,7 +205,7 @@ if (!defined('COMET_CACHE_EXCLUDE_REFS')) {
195
  define('COMET_CACHE_EXCLUDE_REFS', '%%COMET_CACHE_EXCLUDE_REFS%%');
196
  }
197
  if (!defined('COMET_CACHE_EXCLUDE_AGENTS')) {
198
- /**
199
  * HTTP user-agent exclusions.
200
  *
201
  * @since 140422 First documented version.
@@ -205,7 +215,7 @@ if (!defined('COMET_CACHE_EXCLUDE_AGENTS')) {
205
  define('COMET_CACHE_EXCLUDE_AGENTS', '%%COMET_CACHE_EXCLUDE_AGENTS%%');
206
  }
207
  if (!defined('COMET_CACHE_404_CACHE_FILENAME')) {
208
- /**
209
  * 404 file name (if applicable).
210
  *
211
  * @since 140422 First documented version.
@@ -234,10 +244,10 @@ if (!defined('COMET_CACHE_404_CACHE_FILENAME')) {
234
  $GLOBALS[GLOBAL_NS.'_advanced_cache'] = new Classes\AdvancedCache();
235
  $GLOBALS[GLOBAL_NS.'__advanced_cache'] = &$GLOBALS[GLOBAL_NS.'_advanced_cache'];
236
  if (!isset($GLOBALS['zencache__advanced_cache'])) {
237
- $GLOBALS['zencache_advanced_cache'] = &$GLOBALS[GLOBAL_NS.'_advanced_cache'];
238
  $GLOBALS['zencache__advanced_cache'] = &$GLOBALS[GLOBAL_NS.'_advanced_cache'];
239
  }
240
  if (!isset($GLOBALS['quick_cache__advanced_cache'])) {
241
- $GLOBALS['quick_cache_advanced_cache'] = &$GLOBALS[GLOBAL_NS.'_advanced_cache'];
242
  $GLOBALS['quick_cache__advanced_cache'] = &$GLOBALS[GLOBAL_NS.'_advanced_cache'];
243
  }
12
  exit('Do NOT access this file directly: '.basename(__FILE__));
13
  }
14
  if (!defined('COMET_CACHE_PLUGIN_FILE')) {
15
+ /*
16
  * Plugin file path.
17
  *
18
  * @since 140725 Reorganizing class members.
23
  }
24
  if (defined('WP_DEBUG') && WP_DEBUG) {
25
  if ((include_once(dirname(COMET_CACHE_PLUGIN_FILE).'/src/includes/stub.php')) === false) {
26
+ return; // Unable to find stub. Fail softly w/ PHP warning.
27
  }
28
  } elseif ((@include_once(dirname(COMET_CACHE_PLUGIN_FILE).'/src/includes/stub.php')) === false) {
29
  return; // Unable to find stub. Fail softly.
30
  }
31
  if (defined('WP_DEBUG') && WP_DEBUG) {
32
+ if ((include_once(dirname(COMET_CACHE_PLUGIN_FILE).'/src/includes/functions/wp-cache-postload.php')) === false) {
33
+ return; // Unable to find postload function(s). Fail softly w/ PHP warning.
34
  }
35
  } elseif ((@include_once(dirname(COMET_CACHE_PLUGIN_FILE).'/src/includes/functions/wp-cache-postload.php')) === false) {
36
  return; // Unable to find postload function(s). Fail softly.
40
  Classes\AdvCacheBackCompat::browserCacheConstant();
41
 
42
  if (!defined('COMET_CACHE_PRO')) {
43
+ /*
44
  * Comet Cache Pro flag.
45
  *
46
  * @since 140422 First documented version.
50
  define('COMET_CACHE_PRO', IS_PRO);
51
  }
52
  if (!defined('COMET_CACHE_ENABLE')) {
53
+ /*
54
  * Is Comet Cache enabled?
55
  *
56
  * @since 140422 First documented version.
60
  define('COMET_CACHE_ENABLE', '%%COMET_CACHE_ENABLE%%');
61
  }
62
  if (!defined('COMET_CACHE_DEBUGGING_ENABLE')) {
63
+ /*
64
  * Is Comet Cache debugging enabled?
65
  *
66
  * @since 140422 First documented version.
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
  *
76
  * @since 140422 First documented version.
83
  define('COMET_CACHE_ALLOW_CLIENT_SIDE_CACHE', '%%COMET_CACHE_ALLOW_CLIENT_SIDE_CACHE%%');
84
  }
85
  if (!defined('COMET_CACHE_GET_REQUESTS')) {
86
+ /*
87
  * Cache `$_GET` requests w/ a query string?
88
  *
89
  * @since 140422 First documented version.
92
  */
93
  define('COMET_CACHE_GET_REQUESTS', '%%COMET_CACHE_GET_REQUESTS%%');
94
  }
95
+ if (!defined('COMET_CACHE_IGNORE_GET_REQUEST_VARS')) {
96
+ /*
97
+ * Ignore `$_GET` request query vars?
98
+ *
99
+ * @since 161119 First documented version.
100
+ *
101
+ * @var string A regular expression; else an empty string.
102
+ */
103
+ define('COMET_CACHE_IGNORE_GET_REQUEST_VARS', '%%COMET_CACHE_IGNORE_GET_REQUEST_VARS%%');
104
+ }
105
  if (!defined('COMET_CACHE_CACHE_404_REQUESTS')) {
106
+ /*
107
  * Cache 404 errors?
108
  *
109
  * @since 140422 First documented version.
113
  define('COMET_CACHE_CACHE_404_REQUESTS', '%%COMET_CACHE_CACHE_404_REQUESTS%%');
114
  }
115
  if (!defined('COMET_CACHE_CACHE_NONCE_VALUES')) {
116
+ /*
117
  * Cache HTML containing nonce values?
118
  *
119
  * @since 160103 First documented version.
123
  define('COMET_CACHE_CACHE_NONCE_VALUES', '%%COMET_CACHE_CACHE_NONCE_VALUES%%');
124
  }
125
  if (!defined('COMET_CACHE_CACHE_NONCE_VALUES_WHEN_LOGGED_IN')) {
126
+ /*
127
  * Cache HTML containing nonce values for Logged-In Users?
128
  *
129
  * @since 160103 First documented version.
133
  define('COMET_CACHE_CACHE_NONCE_VALUES_WHEN_LOGGED_IN', '%%COMET_CACHE_CACHE_NONCE_VALUES_WHEN_LOGGED_IN%%');
134
  }
135
  if (!defined('COMET_CACHE_FEEDS_ENABLE')) {
136
+ /*
137
  * Cache XML/RSS/Atom feeds?
138
  *
139
  * @since 140422 First documented version.
144
  }
145
 
146
  if (!defined('COMET_CACHE_DIR')) {
147
+ /*
148
  * Directory used to store cache files; relative to `WP_CONTENT_DIR`.
149
  *
150
  * @since 140422 First documented version.
154
  define('COMET_CACHE_DIR', WP_CONTENT_DIR.'/'.'%%COMET_CACHE_DIR%%');
155
  }
156
  if (!defined('COMET_CACHE_MAX_AGE')) {
157
+ /*
158
  * Cache expiration time.
159
  *
160
  * @since 140422 First documented version.
165
  }
166
 
167
  if (!defined('COMET_CACHE_EXCLUDE_HOSTS')) {
168
+ /*
169
  * Host exclusions.
170
  *
171
  * @since 160706 Adding host exclusions.
175
  define('COMET_CACHE_EXCLUDE_HOSTS', '%%COMET_CACHE_EXCLUDE_HOSTS%%');
176
  }
177
  if (!defined('COMET_CACHE_EXCLUDE_URIS')) {
178
+ /*
179
  * URI exclusions.
180
  *
181
  * @since 140422 First documented version.
185
  define('COMET_CACHE_EXCLUDE_URIS', '%%COMET_CACHE_EXCLUDE_URIS%%');
186
  }
187
  if (!defined('COMET_CACHE_EXCLUDE_CLIENT_SIDE_URIS')) {
188
+ /*
189
  * Client-side URI exclusions.
190
  *
191
  * @since 151220 Adding support for client-side URI exclusions.
195
  define('COMET_CACHE_EXCLUDE_CLIENT_SIDE_URIS', '%%COMET_CACHE_EXCLUDE_CLIENT_SIDE_URIS%%');
196
  }
197
  if (!defined('COMET_CACHE_EXCLUDE_REFS')) {
198
+ /*
199
  * HTTP referrer exclusions.
200
  *
201
  * @since 140422 First documented version.
205
  define('COMET_CACHE_EXCLUDE_REFS', '%%COMET_CACHE_EXCLUDE_REFS%%');
206
  }
207
  if (!defined('COMET_CACHE_EXCLUDE_AGENTS')) {
208
+ /*
209
  * HTTP user-agent exclusions.
210
  *
211
  * @since 140422 First documented version.
215
  define('COMET_CACHE_EXCLUDE_AGENTS', '%%COMET_CACHE_EXCLUDE_AGENTS%%');
216
  }
217
  if (!defined('COMET_CACHE_404_CACHE_FILENAME')) {
218
+ /*
219
  * 404 file name (if applicable).
220
  *
221
  * @since 140422 First documented version.
244
  $GLOBALS[GLOBAL_NS.'_advanced_cache'] = new Classes\AdvancedCache();
245
  $GLOBALS[GLOBAL_NS.'__advanced_cache'] = &$GLOBALS[GLOBAL_NS.'_advanced_cache'];
246
  if (!isset($GLOBALS['zencache__advanced_cache'])) {
247
+ $GLOBALS['zencache_advanced_cache'] = &$GLOBALS[GLOBAL_NS.'_advanced_cache'];
248
  $GLOBALS['zencache__advanced_cache'] = &$GLOBALS[GLOBAL_NS.'_advanced_cache'];
249
  }
250
  if (!isset($GLOBALS['quick_cache__advanced_cache'])) {
251
+ $GLOBALS['quick_cache_advanced_cache'] = &$GLOBALS[GLOBAL_NS.'_advanced_cache'];
252
  $GLOBALS['quick_cache__advanced_cache'] = &$GLOBALS[GLOBAL_NS.'_advanced_cache'];
253
  }
src/includes/templates/htaccess/canonical-urls-no-ts-enable.txt CHANGED
@@ -14,5 +14,5 @@
14
  RewriteCond %{REQUEST_URI} /$
15
 
16
  # Force NO trailing slash on all virtual requests.
17
- RewriteRule ^(.*)/$ /$1 [QSA,L,R=301]
18
  </IfModule>
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 CHANGED
@@ -14,5 +14,5 @@
14
  RewriteCond %{REQUEST_URI} !/$
15
 
16
  # Force a trailing slash on all virtual requests.
17
- RewriteRule ^(.*)$ /$1/ [QSA,L,R=301]
18
  </IfModule>
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/traits/Ac/ClientSideUtils.php CHANGED
@@ -6,25 +6,23 @@ use WebSharks\CometCache\Classes;
6
  trait ClientSideUtils
7
  {
8
  /**
9
- * Sends no-cache headers (if applicable).
10
  *
11
- * @since 150422 Rewrite. Enhanced/altered 151220.
 
 
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
  }
@@ -32,11 +30,10 @@ trait ClientSideUtils
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`.
40
  }
41
  return $this->sendNoCacheHeaders(); // Disallow; default behavior in this mode.
42
  }
6
  trait ClientSideUtils
7
  {
8
  /**
9
+ * Sends no-cache headers.
10
  *
11
+ * @since 150422 Rewrite.
12
+ * @since 151220 Enhancing.
13
+ * @since 161119 Enhancing.
14
  */
15
  public function maybeStopBrowserCaching()
16
  {
17
+ $short_name_lc = mb_strtolower(SHORT_NAME); // Needed below.
 
 
 
 
18
 
19
+ switch (defined('COMET_CACHE_ALLOW_CLIENT_SIDE_CACHE') ? (bool) COMET_CACHE_ALLOW_CLIENT_SIDE_CACHE : false) {
20
+ case true: // If global config allows; check exclusions.
21
 
22
+ if (isset($_GET[$short_name_lc.'ABC'])) {
23
+ if (!filter_var($_GET[$short_name_lc.'ABC'], FILTER_VALIDATE_BOOLEAN)) {
24
  return $this->sendNoCacheHeaders(); // Disallow.
25
+ } // Else, allow client-side caching because `ABC` is a true-ish value.
 
26
  } elseif (COMET_CACHE_EXCLUDE_CLIENT_SIDE_URIS && (empty($_SERVER['REQUEST_URI']) || preg_match(COMET_CACHE_EXCLUDE_CLIENT_SIDE_URIS, $_SERVER['REQUEST_URI']))) {
27
  return $this->sendNoCacheHeaders(); // Disallow.
28
  }
30
 
31
  case false: // Global config disallows; check inclusions.
32
 
33
+ if (isset($_GET[$short_name_lc.'ABC'])) {
34
+ if (filter_var($_GET[$short_name_lc.'ABC'], FILTER_VALIDATE_BOOLEAN)) {
35
  return; // Allow, because `ABC` is a false-ish value.
36
+ } // Else, disallow client-side caching because `ABC` is a true-ish value.
 
37
  }
38
  return $this->sendNoCacheHeaders(); // Disallow; default behavior in this mode.
39
  }
src/includes/traits/Ac/NcDebugUtils.php CHANGED
@@ -10,7 +10,7 @@ trait NcDebugUtils
10
  *
11
  * @since 150422 Rewrite.
12
  *
13
- * @type array An array of debug info; i.e. `reason_code` and `reason` (optional).
14
  */
15
  public $debug_info = ['reason_code' => '', 'reason' => ''];
16
 
@@ -144,11 +144,11 @@ trait NcDebugUtils
144
  break; // Break switch handler.
145
 
146
  case $this::NC_DEBUG_IS_LOGGED_IN_USER_NONCE:
147
- $reason = __('because the current page contains `_wpnonce` or `akismet_comment_nonce`. While your current configuration states that pages SHOULD be cache for logged-in visitors, `*nonce*` values in the markup are not cache-compatible. See http://wsharks.com/1O1Kudy for further details.', 'comet-cache');
148
  break; // Break switch handler.
149
 
150
  case $this::NC_DEBUG_PAGE_CONTAINS_NONCE:
151
- $reason = __('because the current page contains `_wpnonce` or `akismet_comment_nonce`. Note that `*nonce*` values in the markup are not cache-compatible. See http://wsharks.com/1O1Kudy for further details.', 'comet-cache');
152
  break; // Break switch handler.
153
 
154
  case $this::NC_DEBUG_NO_USER_TOKEN:
10
  *
11
  * @since 150422 Rewrite.
12
  *
13
+ * @var array An array of debug info; i.e. `reason_code` and `reason` (optional).
14
  */
15
  public $debug_info = ['reason_code' => '', 'reason' => ''];
16
 
144
  break; // Break switch handler.
145
 
146
  case $this::NC_DEBUG_IS_LOGGED_IN_USER_NONCE:
147
+ $reason = __('because the current page contains `_wpnonce` or `akismet_comment_nonce`. While your current configuration states that pages should be cached for logged-in visitors, it also states that pages with dynamic `*nonce*` values in the markup should not be cached, even for logged-in visitors. See http://wsharks.com/1O1Kudy for further details.', 'comet-cache');
148
  break; // Break switch handler.
149
 
150
  case $this::NC_DEBUG_PAGE_CONTAINS_NONCE:
151
+ $reason = __('because the current page contains `_wpnonce` or `akismet_comment_nonce`. Your current configuration states that pages with dynamic `*nonce*` values in the markup should not be cached. See http://wsharks.com/1O1Kudy for further details.', 'comet-cache');
152
  break; // Break switch handler.
153
 
154
  case $this::NC_DEBUG_NO_USER_TOKEN:
src/includes/traits/Ac/ObUtils.php CHANGED
@@ -10,7 +10,7 @@ trait ObUtils
10
  *
11
  * @since 150422 Rewrite.
12
  *
13
- * @type float One of `http://` or `https://`.
14
  */
15
  public $protocol = '';
16
 
@@ -19,7 +19,7 @@ trait ObUtils
19
  *
20
  * @since 150821 Improving multisite compat.
21
  *
22
- * @type string Host token for this request.
23
  */
24
  public $host_token = '';
25
 
@@ -28,7 +28,7 @@ trait ObUtils
28
  *
29
  * @since 150821 Improving multisite compat.
30
  *
31
- * @type string Host base/dir tokens for this request.
32
  */
33
  public $host_base_dir_tokens = '';
34
 
@@ -37,7 +37,7 @@ trait ObUtils
37
  *
38
  * @since 150422 Rewrite.
39
  *
40
- * @type string|mixed Any scalar value does fine.
41
  */
42
  public $version_salt = '';
43
 
@@ -46,7 +46,7 @@ trait ObUtils
46
  *
47
  * @since 150422 Rewrite.
48
  *
49
- * @type string Cache path for the current request.
50
  */
51
  public $cache_path = '';
52
 
@@ -55,7 +55,7 @@ trait ObUtils
55
  *
56
  * @since 150422 Rewrite.
57
  *
58
- * @type string Absolute cache file path for the current request.
59
  */
60
  public $cache_file = '';
61
 
@@ -64,7 +64,7 @@ trait ObUtils
64
  *
65
  * @since 150422 Rewrite.
66
  *
67
- * @type string 404 cache path for the current request.
68
  */
69
  public $cache_path_404 = '';
70
 
@@ -73,7 +73,7 @@ trait ObUtils
73
  *
74
  * @since 150422 Rewrite.
75
  *
76
- * @type string Absolute 404 cache file path for the current request.
77
  */
78
  public $cache_file_404 = '';
79
 
@@ -82,7 +82,7 @@ trait ObUtils
82
  *
83
  * @since 150422 Rewrite.
84
  *
85
- * @type string Version salt followed by the current request location.
86
  */
87
  public $salt_location = '';
88
 
@@ -91,10 +91,19 @@ trait ObUtils
91
  *
92
  * @since 151002 Load average checks in pro version.
93
  *
94
- * @type int Calculated max age; i.e., before expiration.
95
  */
96
  public $cache_max_age = 0;
97
 
 
 
 
 
 
 
 
 
 
98
  /**
99
  * Start output buffering (if applicable); or serve a cache file (if possible).
100
  *
@@ -120,7 +129,7 @@ trait ObUtils
120
  if (isset($_SERVER['COMET_CACHE_ALLOWED']) && !$_SERVER['COMET_CACHE_ALLOWED']) {
121
  return $this->maybeSetDebugInfo($this::NC_DEBUG_COMET_CACHE_ALLOWED_SERVER_VAR);
122
  }
123
- if (defined('DONOTCACHEPAGE')) {
124
  return $this->maybeSetDebugInfo($this::NC_DEBUG_DONOTCACHEPAGE_CONSTANT);
125
  }
126
  if (isset($_SERVER['DONOTCACHEPAGE'])) {
@@ -135,7 +144,7 @@ trait ObUtils
135
  if (isset($_SERVER['SERVER_ADDR']) && $this->currentIp() === $_SERVER['SERVER_ADDR']) {
136
  if ((!IS_PRO || !$this->isAutoCacheEngine()) && !$this->isLocalhost()) {
137
  return $this->maybeSetDebugInfo($this::NC_DEBUG_SELF_SERVE_REQUEST);
138
- }
139
  }
140
  if (!COMET_CACHE_FEEDS_ENABLE && $this->isFeed()) {
141
  return $this->maybeSetDebugInfo($this::NC_DEBUG_FEED_REQUEST);
@@ -155,7 +164,7 @@ trait ObUtils
155
  if (!COMET_CACHE_GET_REQUESTS && $this->requestContainsUncacheableQueryVars()) {
156
  return $this->maybeSetDebugInfo($this::NC_DEBUG_GET_REQUEST_QUERIES);
157
  }
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'])) {
@@ -167,21 +176,21 @@ trait ObUtils
167
  if (COMET_CACHE_EXCLUDE_AGENTS && !empty($_SERVER['HTTP_USER_AGENT']) && (!IS_PRO || !$this->isAutoCacheEngine())) {
168
  if (preg_match(COMET_CACHE_EXCLUDE_AGENTS, $_SERVER['HTTP_USER_AGENT'])) {
169
  return $this->maybeSetDebugInfo($this::NC_DEBUG_EXCLUDED_AGENTS);
170
- }
171
  }
172
  if (COMET_CACHE_EXCLUDE_REFS && !empty($_REQUEST['_wp_http_referer'])) {
173
  if (preg_match(COMET_CACHE_EXCLUDE_REFS, stripslashes($_REQUEST['_wp_http_referer']))) {
174
  return $this->maybeSetDebugInfo($this::NC_DEBUG_EXCLUDED_REFS);
175
- }
176
  }
177
  if (COMET_CACHE_EXCLUDE_REFS && !empty($_SERVER['HTTP_REFERER'])) {
178
  if (preg_match(COMET_CACHE_EXCLUDE_REFS, $_SERVER['HTTP_REFERER'])) {
179
  return $this->maybeSetDebugInfo($this::NC_DEBUG_EXCLUDED_REFS);
180
- }
181
  }
182
- $this->protocol = $this->isSsl() ? 'https://' : 'http://';
183
  $this->host_token = $this->hostToken();
184
  $this->host_base_dir_tokens = $this->hostBaseDirTokens();
 
185
 
186
  $this->version_salt = ''; // Initialize the version salt.
187
 
@@ -196,8 +205,11 @@ trait ObUtils
196
 
197
  $this->salt_location = ltrim($this->version_salt.' '.$this->protocol.$this->host_token.$_SERVER['REQUEST_URI']);
198
 
199
- $this->cache_max_age = strtotime('-'.COMET_CACHE_MAX_AGE);
 
 
200
 
 
201
  if (IS_PRO && COMET_CACHE_WHEN_LOGGED_IN === 'postload' && $this->isLikeUserLoggedIn()) {
202
  $this->postload['when_logged_in'] = true; // Enable postload check.
203
  } elseif (is_file($this->cache_file) && (!$this->cache_max_age || filemtime($this->cache_file) >= $this->cache_max_age)) {
@@ -213,9 +225,16 @@ trait ObUtils
213
 
214
  if (COMET_CACHE_DEBUGGING_ENABLE && $this->isHtmlXmlDoc($cache)) {
215
  $total_time = number_format(microtime(true) - $this->timer, 5, '.', '');
216
- $cache .= "\n".'<!-- +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->';
217
- // translators: This string is actually NOT translatable because the `__()` function is not available at this point in the processing.
218
- $cache .= "\n".'<!-- '.htmlspecialchars(sprintf(__('%1$s fully functional :-) Cache file served for (%2$s) in %3$s seconds, on: %4$s.', 'comet-cache'), NAME, $this->salt_location, $total_time, date('M jS, Y @ g:i a T'))).' -->';
 
 
 
 
 
 
 
219
  }
220
  exit($cache); // Exit with cache contents.
221
  } else {
@@ -254,54 +273,54 @@ trait ObUtils
254
  return false; // Don't cache an empty buffer.
255
  }
256
  if (!isset($GLOBALS[GLOBAL_NS.'_shutdown_flag'])) {
257
- return (boolean) $this->maybeSetDebugInfo($this::NC_DEBUG_EARLY_BUFFER_TERMINATION);
258
  }
259
  if (defined('COMET_CACHE_ALLOWED') && !COMET_CACHE_ALLOWED) {
260
- return (boolean) $this->maybeSetDebugInfo($this::NC_DEBUG_COMET_CACHE_ALLOWED_CONSTANT);
261
  }
262
  if (isset($_SERVER['COMET_CACHE_ALLOWED']) && !$_SERVER['COMET_CACHE_ALLOWED']) {
263
- return (boolean) $this->maybeSetDebugInfo($this::NC_DEBUG_COMET_CACHE_ALLOWED_SERVER_VAR);
264
  }
265
  if (defined('DONOTCACHEPAGE')) {
266
- return (boolean) $this->maybeSetDebugInfo($this::NC_DEBUG_DONOTCACHEPAGE_CONSTANT);
267
  }
268
  if (isset($_SERVER['DONOTCACHEPAGE'])) {
269
- return (boolean) $this->maybeSetDebugInfo($this::NC_DEBUG_DONOTCACHEPAGE_SERVER_VAR);
270
  }
271
  if ((!IS_PRO || !COMET_CACHE_WHEN_LOGGED_IN) && $this->is_user_logged_in) {
272
- return (boolean) $this->maybeSetDebugInfo($this::NC_DEBUG_IS_LOGGED_IN_USER);
273
  }
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);
281
  }
282
  } else { // Use the default debug notice for nonce conflicts.
283
- return (boolean) $this->maybeSetDebugInfo($this::NC_DEBUG_PAGE_CONTAINS_NONCE);
284
  } // An nonce makes the page dynamic; i.e., NOT cache compatible.
285
  }
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()) {
293
- return (boolean) $this->maybeSetDebugInfo($this::NC_DEBUG_UNCACHEABLE_CONTENT_TYPE);
294
  }
295
  if (!$this->hasACacheableStatus()) {
296
- return (boolean) $this->maybeSetDebugInfo($this::NC_DEBUG_UNCACHEABLE_STATUS);
297
  }
298
  if ($this->is_maintenance) {
299
- return (boolean) $this->maybeSetDebugInfo($this::NC_DEBUG_MAINTENANCE_PLUGIN);
300
  }
301
  if ($this->functionIsPossible('zlib_get_coding_type') && zlib_get_coding_type()
302
  && (!($zlib_oc = ini_get('zlib.output_compression')) || !filter_var($zlib_oc, FILTER_VALIDATE_BOOLEAN))
303
  ) {
304
- return (boolean) $this->maybeSetDebugInfo($this::NC_DEBUG_OB_ZLIB_CODING_TYPE);
305
  }
306
  # Lock the cache directory while writes take place here.
307
 
@@ -329,18 +348,48 @@ trait ObUtils
329
  throw new \Exception(sprintf(__('Unable to create symlink: `%1$s` » `%2$s`. Possible permissions issue (or race condition), please check your cache directory: `%3$s`.', 'comet-cache'), $this->cache_file, $this->cache_file_404, COMET_CACHE_DIR));
330
  }
331
  $this->cacheUnlock($cache_lock); // Release.
332
- return (boolean) $this->maybeSetDebugInfo($this::NC_DEBUG_1ST_TIME_404_SYMLINK);
333
  }
334
  /* ------- Otherwise, we need to construct & store a new cache file. ----------------------------------------------- */
335
 
336
 
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) {
346
  if (file_put_contents($cache_file_tmp, serialize($this->cacheableHeadersList()).'<!--headers-->'.$cache) && rename($cache_file_tmp, $this->cache_file_404)) {
10
  *
11
  * @since 150422 Rewrite.
12
  *
13
+ * @var float One of `http://` or `https://`.
14
  */
15
  public $protocol = '';
16
 
19
  *
20
  * @since 150821 Improving multisite compat.
21
  *
22
+ * @var string Host token for this request.
23
  */
24
  public $host_token = '';
25
 
28
  *
29
  * @since 150821 Improving multisite compat.
30
  *
31
+ * @var string Host base/dir tokens for this request.
32
  */
33
  public $host_base_dir_tokens = '';
34
 
37
  *
38
  * @since 150422 Rewrite.
39
  *
40
+ * @var string|mixed Any scalar value does fine.
41
  */
42
  public $version_salt = '';
43
 
46
  *
47
  * @since 150422 Rewrite.
48
  *
49
+ * @var string Cache path for the current request.
50
  */
51
  public $cache_path = '';
52
 
55
  *
56
  * @since 150422 Rewrite.
57
  *
58
+ * @var string Absolute cache file path for the current request.
59
  */
60
  public $cache_file = '';
61
 
64
  *
65
  * @since 150422 Rewrite.
66
  *
67
+ * @var string 404 cache path for the current request.
68
  */
69
  public $cache_path_404 = '';
70
 
73
  *
74
  * @since 150422 Rewrite.
75
  *
76
+ * @var string Absolute 404 cache file path for the current request.
77
  */
78
  public $cache_file_404 = '';
79
 
82
  *
83
  * @since 150422 Rewrite.
84
  *
85
+ * @var string Version salt followed by the current request location.
86
  */
87
  public $salt_location = '';
88
 
91
  *
92
  * @since 151002 Load average checks in pro version.
93
  *
94
+ * @var int Calculated max age; i.e., before expiration.
95
  */
96
  public $cache_max_age = 0;
97
 
98
+ /**
99
+ * Calculated 12 hour expiration time.
100
+ *
101
+ * @since 161119 Calculated 12 hour expiration time.
102
+ *
103
+ * @var int Calculated 12 hour expiration time.
104
+ */
105
+ public $nonce_cache_max_age = 0;
106
+
107
  /**
108
  * Start output buffering (if applicable); or serve a cache file (if possible).
109
  *
129
  if (isset($_SERVER['COMET_CACHE_ALLOWED']) && !$_SERVER['COMET_CACHE_ALLOWED']) {
130
  return $this->maybeSetDebugInfo($this::NC_DEBUG_COMET_CACHE_ALLOWED_SERVER_VAR);
131
  }
132
+ if (defined('DONOTCACHEPAGE')) { // Common to most WP cache plugins.
133
  return $this->maybeSetDebugInfo($this::NC_DEBUG_DONOTCACHEPAGE_CONSTANT);
134
  }
135
  if (isset($_SERVER['DONOTCACHEPAGE'])) {
144
  if (isset($_SERVER['SERVER_ADDR']) && $this->currentIp() === $_SERVER['SERVER_ADDR']) {
145
  if ((!IS_PRO || !$this->isAutoCacheEngine()) && !$this->isLocalhost()) {
146
  return $this->maybeSetDebugInfo($this::NC_DEBUG_SELF_SERVE_REQUEST);
147
+ } // Don't trip on requests by the auto-cache engine.
148
  }
149
  if (!COMET_CACHE_FEEDS_ENABLE && $this->isFeed()) {
150
  return $this->maybeSetDebugInfo($this::NC_DEBUG_FEED_REQUEST);
164
  if (!COMET_CACHE_GET_REQUESTS && $this->requestContainsUncacheableQueryVars()) {
165
  return $this->maybeSetDebugInfo($this::NC_DEBUG_GET_REQUEST_QUERIES);
166
  }
167
+ if (!empty($_REQUEST['preview'])) { // Don't cache previews under any circumstance.
168
  return $this->maybeSetDebugInfo($this::NC_DEBUG_PREVIEW);
169
  }
170
  if (COMET_CACHE_EXCLUDE_HOSTS && preg_match(COMET_CACHE_EXCLUDE_HOSTS, $_SERVER['HTTP_HOST'])) {
176
  if (COMET_CACHE_EXCLUDE_AGENTS && !empty($_SERVER['HTTP_USER_AGENT']) && (!IS_PRO || !$this->isAutoCacheEngine())) {
177
  if (preg_match(COMET_CACHE_EXCLUDE_AGENTS, $_SERVER['HTTP_USER_AGENT'])) {
178
  return $this->maybeSetDebugInfo($this::NC_DEBUG_EXCLUDED_AGENTS);
179
+ } // Don't trip on requests by the auto-cache engine.
180
  }
181
  if (COMET_CACHE_EXCLUDE_REFS && !empty($_REQUEST['_wp_http_referer'])) {
182
  if (preg_match(COMET_CACHE_EXCLUDE_REFS, stripslashes($_REQUEST['_wp_http_referer']))) {
183
  return $this->maybeSetDebugInfo($this::NC_DEBUG_EXCLUDED_REFS);
184
+ } // This variable is set by WordPress core in some cases.
185
  }
186
  if (COMET_CACHE_EXCLUDE_REFS && !empty($_SERVER['HTTP_REFERER'])) {
187
  if (preg_match(COMET_CACHE_EXCLUDE_REFS, $_SERVER['HTTP_REFERER'])) {
188
  return $this->maybeSetDebugInfo($this::NC_DEBUG_EXCLUDED_REFS);
189
+ } // Based on the HTTP referrer in this case.
190
  }
 
191
  $this->host_token = $this->hostToken();
192
  $this->host_base_dir_tokens = $this->hostBaseDirTokens();
193
+ $this->protocol = $this->isSsl() ? 'https://' : 'http://';
194
 
195
  $this->version_salt = ''; // Initialize the version salt.
196
 
205
 
206
  $this->salt_location = ltrim($this->version_salt.' '.$this->protocol.$this->host_token.$_SERVER['REQUEST_URI']);
207
 
208
+ $this->cache_max_age = strtotime('-'.COMET_CACHE_MAX_AGE); // Initialize; global config.
209
+ $this->nonce_cache_max_age = strtotime('-12 hours'); // Initialize; based on a fixed expiration time.
210
+
211
 
212
+
213
  if (IS_PRO && COMET_CACHE_WHEN_LOGGED_IN === 'postload' && $this->isLikeUserLoggedIn()) {
214
  $this->postload['when_logged_in'] = true; // Enable postload check.
215
  } elseif (is_file($this->cache_file) && (!$this->cache_max_age || filemtime($this->cache_file) >= $this->cache_max_age)) {
225
 
226
  if (COMET_CACHE_DEBUGGING_ENABLE && $this->isHtmlXmlDoc($cache)) {
227
  $total_time = number_format(microtime(true) - $this->timer, 5, '.', '');
228
+
229
+ $DebugNotes = new Classes\Notes();
230
+
231
+ $DebugNotes->addAsciiArt(sprintf(__('%1$s is Fully Functional', 'comet-cache'), NAME));
232
+ $DebugNotes->addLineBreak();
233
+
234
+ $DebugNotes->add(__('Loaded via Cache On', 'comet-cache'), date('M jS, Y @ g:i a T'));
235
+ $DebugNotes->add(__('Loaded via Cache In', 'comet-cache'), sprintf(__('%1$s seconds', 'comet-cache'), $total_time));
236
+
237
+ $cache .= "\n\n".$DebugNotes->asHtmlComments();
238
  }
239
  exit($cache); // Exit with cache contents.
240
  } else {
273
  return false; // Don't cache an empty buffer.
274
  }
275
  if (!isset($GLOBALS[GLOBAL_NS.'_shutdown_flag'])) {
276
+ return (bool) $this->maybeSetDebugInfo($this::NC_DEBUG_EARLY_BUFFER_TERMINATION);
277
  }
278
  if (defined('COMET_CACHE_ALLOWED') && !COMET_CACHE_ALLOWED) {
279
+ return (bool) $this->maybeSetDebugInfo($this::NC_DEBUG_COMET_CACHE_ALLOWED_CONSTANT);
280
  }
281
  if (isset($_SERVER['COMET_CACHE_ALLOWED']) && !$_SERVER['COMET_CACHE_ALLOWED']) {
282
+ return (bool) $this->maybeSetDebugInfo($this::NC_DEBUG_COMET_CACHE_ALLOWED_SERVER_VAR);
283
  }
284
  if (defined('DONOTCACHEPAGE')) {
285
+ return (bool) $this->maybeSetDebugInfo($this::NC_DEBUG_DONOTCACHEPAGE_CONSTANT);
286
  }
287
  if (isset($_SERVER['DONOTCACHEPAGE'])) {
288
+ return (bool) $this->maybeSetDebugInfo($this::NC_DEBUG_DONOTCACHEPAGE_SERVER_VAR);
289
  }
290
  if ((!IS_PRO || !COMET_CACHE_WHEN_LOGGED_IN) && $this->is_user_logged_in) {
291
+ return (bool) $this->maybeSetDebugInfo($this::NC_DEBUG_IS_LOGGED_IN_USER);
292
  }
293
  if ((!IS_PRO || !COMET_CACHE_WHEN_LOGGED_IN) && $this->isLikeUserLoggedIn()) {
294
+ return (bool) $this->maybeSetDebugInfo($this::NC_DEBUG_IS_LIKE_LOGGED_IN_USER);
295
  }
296
  if (!COMET_CACHE_CACHE_NONCE_VALUES && preg_match('/\b(?:_wpnonce|akismet_comment_nonce)\b/u', $cache)) {
297
  if (IS_PRO && COMET_CACHE_WHEN_LOGGED_IN && $this->isLikeUserLoggedIn()) {
298
  if (!COMET_CACHE_CACHE_NONCE_VALUES_WHEN_LOGGED_IN) {
299
+ return (bool) $this->maybeSetDebugInfo($this::NC_DEBUG_IS_LOGGED_IN_USER_NONCE);
300
  }
301
  } else { // Use the default debug notice for nonce conflicts.
302
+ return (bool) $this->maybeSetDebugInfo($this::NC_DEBUG_PAGE_CONTAINS_NONCE);
303
  } // An nonce makes the page dynamic; i.e., NOT cache compatible.
304
  }
305
  if ($this->is_404 && !COMET_CACHE_CACHE_404_REQUESTS) {
306
+ return (bool) $this->maybeSetDebugInfo($this::NC_DEBUG_404_REQUEST);
307
  }
308
  if (mb_stripos($cache, '<body id="error-page">') !== false) {
309
+ return (bool) $this->maybeSetDebugInfo($this::NC_DEBUG_WP_ERROR_PAGE);
310
  }
311
  if (!$this->hasACacheableContentType()) {
312
+ return (bool) $this->maybeSetDebugInfo($this::NC_DEBUG_UNCACHEABLE_CONTENT_TYPE);
313
  }
314
  if (!$this->hasACacheableStatus()) {
315
+ return (bool) $this->maybeSetDebugInfo($this::NC_DEBUG_UNCACHEABLE_STATUS);
316
  }
317
  if ($this->is_maintenance) {
318
+ return (bool) $this->maybeSetDebugInfo($this::NC_DEBUG_MAINTENANCE_PLUGIN);
319
  }
320
  if ($this->functionIsPossible('zlib_get_coding_type') && zlib_get_coding_type()
321
  && (!($zlib_oc = ini_get('zlib.output_compression')) || !filter_var($zlib_oc, FILTER_VALIDATE_BOOLEAN))
322
  ) {
323
+ return (bool) $this->maybeSetDebugInfo($this::NC_DEBUG_OB_ZLIB_CODING_TYPE);
324
  }
325
  # Lock the cache directory while writes take place here.
326
 
348
  throw new \Exception(sprintf(__('Unable to create symlink: `%1$s` » `%2$s`. Possible permissions issue (or race condition), please check your cache directory: `%3$s`.', 'comet-cache'), $this->cache_file, $this->cache_file_404, COMET_CACHE_DIR));
349
  }
350
  $this->cacheUnlock($cache_lock); // Release.
351
+ return (bool) $this->maybeSetDebugInfo($this::NC_DEBUG_1ST_TIME_404_SYMLINK);
352
  }
353
  /* ------- Otherwise, we need to construct & store a new cache file. ----------------------------------------------- */
354
 
355
 
356
 
357
  if (COMET_CACHE_DEBUGGING_ENABLE && $this->isHtmlXmlDoc($cache)) {
358
+ $total_time = number_format(microtime(true) - $this->timer, 5, '.', '');
359
+ $time = time(); // Needed below for expiration calculation.
360
+
361
+ $DebugNotes = new Classes\Notes();
362
+ $DebugNotes->addAsciiArt(sprintf(__('%1$s Notes', 'comet-cache'), NAME));
363
+ $DebugNotes->addLineBreak();
364
+
365
+ $DebugNotes->add(__('Cache File Version Salt', 'comet-cache'), $this->version_salt ? $this->version_salt : __('n/a', 'comet-cache'));
366
+
367
+ if (IS_PRO && COMET_CACHE_WHEN_LOGGED_IN && $this->user_token) {
368
+ $DebugNotes->add(__('Cache File User Token', 'comet-cache'), $this->user_token);
369
+ }
370
+ $DebugNotes->addLineBreak();
371
+
372
+ $DebugNotes->add(__('Cache File URL', 'comet-cache'), $this->is_404 ? __('404 [error document]', 'comet-cache') : $this->protocol.$this->host_token.$_SERVER['REQUEST_URI']);
373
+ $DebugNotes->add(__('Cache File Path', 'comet-cache'), str_replace(WP_CONTENT_DIR, '', $this->is_404 ? $this->cache_file_404 : $this->cache_file));
374
+
375
+ $DebugNotes->addLineBreak();
376
+
377
+ $DebugNotes->add(__('Cache File Generated Via', 'comet-cache'), IS_PRO && $this->isAutoCacheEngine() ? __('Auto-Cache Engine', 'comet-cache') : __('HTTP request', 'comet-cache'));
378
+ $DebugNotes->add(__('Cache File Generated On', 'comet-cache'), date('M jS, Y @ g:i a T'));
379
+ $DebugNotes->add(__('Cache File Generated In', 'comet-cache'), sprintf(__('%1$s seconds', 'comet-cache'), $total_time));
380
+
381
+ $DebugNotes->addLineBreak();
382
+
383
+ if (IS_PRO && COMET_CACHE_WHEN_LOGGED_IN && $this->cache_max_age < $this->nonce_cache_max_age
384
+ && preg_match('/\b(?:_wpnonce|akismet_comment_nonce)\b/u', $cache)) {
385
+ $DebugNotes->add(__('Cache File Expires Early', 'comet-cache'), __('yes, due to nonce in markup', 'comet-cache'));
386
+ $DebugNotes->add(__('Cache File Expires On', 'comet-cache'), date('M jS, Y @ g:i a T', $time + ($time - $this->nonce_cache_max_age)));
387
+ $DebugNotes->add(__('Cache File Auto-Rebuild On', 'comet-cache'), date('M jS, Y @ g:i a T', $time + ($time - $this->nonce_cache_max_age)));
388
+ } else {
389
+ $DebugNotes->add(__('Cache File Expires On', 'comet-cache'), date('M jS, Y @ g:i a T', $time + ($time - $this->cache_max_age)));
390
+ $DebugNotes->add(__('Cache File Auto-Rebuild On', 'comet-cache'), date('M jS, Y @ g:i a T', $time + ($time - $this->cache_max_age)));
391
+ }
392
+ $cache .= "\n".$DebugNotes->asHtmlComments();
393
  }
394
  if ($this->is_404) {
395
  if (file_put_contents($cache_file_tmp, serialize($this->cacheableHeadersList()).'<!--headers-->'.$cache) && rename($cache_file_tmp, $this->cache_file_404)) {
src/includes/traits/Ac/PostloadUtils.php CHANGED
@@ -10,7 +10,7 @@ trait PostloadUtils
10
  *
11
  * @since 150422 Rewrite.
12
  *
13
- * @type bool `TRUE` if main query has been loaded; else `FALSE`.
14
  *
15
  * @see wpMainQueryPostload()
16
  */
@@ -21,7 +21,7 @@ trait PostloadUtils
21
  *
22
  * @since 150422 Rewrite.
23
  *
24
- * @type bool `TRUE` if is a 404 error; else `FALSE`.
25
  *
26
  * @see wpMainQueryPostload()
27
  */
@@ -32,7 +32,7 @@ trait PostloadUtils
32
  *
33
  * @since 150422 Rewrite.
34
  *
35
- * @type int Last HTTP status code (if applicable).
36
  *
37
  * @see maybeFilterStatusHeaderPostload()
38
  */
@@ -43,7 +43,7 @@ trait PostloadUtils
43
  *
44
  * @since 150422 Rewrite.
45
  *
46
- * @type bool `TRUE` if is a WP content type.
47
  *
48
  * @see wpMainQueryPostload()
49
  */
@@ -54,7 +54,7 @@ trait PostloadUtils
54
  *
55
  * @since 150422 Rewrite.
56
  *
57
- * @type string Current WordPress {@link \content_url()}.
58
  *
59
  * @see wpMainQueryPostload()
60
  */
@@ -65,7 +65,7 @@ trait PostloadUtils
65
  *
66
  * @since 150422 Rewrite.
67
  *
68
- * @type bool `TRUE` if {@link \is_user_loged_in()} else `FALSE`.
69
  *
70
  * @see wpMainQueryPostload()
71
  */
@@ -76,7 +76,7 @@ trait PostloadUtils
76
  *
77
  * @since 150422 Rewrite.
78
  *
79
- * @type bool `TRUE` if {@link \is_maintenance()} else `FALSE`.
80
  *
81
  * @see wpMainQueryPostload()
82
  */
@@ -87,7 +87,7 @@ trait PostloadUtils
87
  *
88
  * @since 150422 Rewrite.
89
  *
90
- * @type array Data and/or flags that work with various postload handlers.
91
  */
92
  public $postload = [
93
 
@@ -119,7 +119,7 @@ trait PostloadUtils
119
  'status_header',
120
  function ($status_header, $status_code) {
121
  if ($status_code > 0) {
122
- $this->http_status = (integer) $status_code;
123
  }
124
  return $status_header;
125
  },
10
  *
11
  * @since 150422 Rewrite.
12
  *
13
+ * @var bool `TRUE` if main query has been loaded; else `FALSE`.
14
  *
15
  * @see wpMainQueryPostload()
16
  */
21
  *
22
  * @since 150422 Rewrite.
23
  *
24
+ * @var bool `TRUE` if is a 404 error; else `FALSE`.
25
  *
26
  * @see wpMainQueryPostload()
27
  */
32
  *
33
  * @since 150422 Rewrite.
34
  *
35
+ * @var int Last HTTP status code (if applicable).
36
  *
37
  * @see maybeFilterStatusHeaderPostload()
38
  */
43
  *
44
  * @since 150422 Rewrite.
45
  *
46
+ * @var bool `TRUE` if is a WP content type.
47
  *
48
  * @see wpMainQueryPostload()
49
  */
54
  *
55
  * @since 150422 Rewrite.
56
  *
57
+ * @var string Current WordPress {@link \content_url()}.
58
  *
59
  * @see wpMainQueryPostload()
60
  */
65
  *
66
  * @since 150422 Rewrite.
67
  *
68
+ * @var bool `TRUE` if {@link \is_user_loged_in()} else `FALSE`.
69
  *
70
  * @see wpMainQueryPostload()
71
  */
76
  *
77
  * @since 150422 Rewrite.
78
  *
79
+ * @var bool `TRUE` if {@link \is_maintenance()} else `FALSE`.
80
  *
81
  * @see wpMainQueryPostload()
82
  */
87
  *
88
  * @since 150422 Rewrite.
89
  *
90
+ * @var array Data and/or flags that work with various postload handlers.
91
  */
92
  public $postload = [
93
 
119
  'status_header',
120
  function ($status_header, $status_code) {
121
  if ($status_code > 0) {
122
+ $this->http_status = (int) $status_code;
123
  }
124
  return $status_header;
125
  },
src/includes/traits/Plugin/AdminBarUtils.php CHANGED
@@ -1,5 +1,4 @@
1
  <?php
2
-
3
  namespace WebSharks\CometCache\Traits\Plugin;
4
 
5
  use WebSharks\CometCache\Classes;
@@ -76,9 +75,9 @@ trait AdminBarUtils
76
  [
77
  'parent' => 'top-secondary',
78
  'id' => GLOBAL_NS.'-wipe',
79
- 'title' => __('Wipe', 'comet-cache'),
80
- 'href' => '#',
81
- 'meta' => [
82
  'title' => __('Wipe Cache (Start Fresh). Clears the cache for all sites in this network at once!', 'comet-cache'),
83
  'class' => '-wipe',
84
  'tabindex' => -1,
@@ -92,9 +91,9 @@ trait AdminBarUtils
92
  [
93
  'parent' => 'top-secondary',
94
  'id' => GLOBAL_NS.'-clear',
95
- 'title' => __('Clear Cache', 'comet-cache'),
96
- 'href' => '#',
97
- 'meta' => [
98
  'title' => is_multisite() && current_user_can($this->network_cap)
99
  ? __('Clear Cache (Start Fresh). Affects the current site only.', 'comet-cache')
100
  : '',
@@ -124,7 +123,7 @@ trait AdminBarUtils
124
  'isMultisite' => is_multisite(),
125
  'currentUserHasCap' => current_user_can($this->cap),
126
  'currentUserHasNetworkCap' => current_user_can($this->network_cap),
127
- 'htmlCompressorEnabled' => (boolean) $this->options['htmlc_enable'],
128
  'ajaxURL' => site_url('/wp-load.php', is_ssl() ? 'https' : 'http'),
129
  'i18n' => [
130
  'name' => NAME,
@@ -172,7 +171,8 @@ trait AdminBarUtils
172
  return; // Nothing to do.
173
  }
174
  $deps = ['jquery', 'admin-bar']; // Plugin dependencies.
175
- if ($this->adminBarShowing('stats')) {
 
176
  $deps[] = 'chartjs'; // Add ChartJS dependency.
177
  wp_enqueue_script('chartjs', set_url_scheme('//cdnjs.cloudflare.com/ajax/libs/Chart.js/1.0.2/Chart.min.js'), [], null, true);
178
  }
1
  <?php
 
2
  namespace WebSharks\CometCache\Traits\Plugin;
3
 
4
  use WebSharks\CometCache\Classes;
75
  [
76
  'parent' => 'top-secondary',
77
  'id' => GLOBAL_NS.'-wipe',
78
+ 'title' => __('Wipe', 'comet-cache'),
79
+ 'href' => '#',
80
+ 'meta' => [
81
  'title' => __('Wipe Cache (Start Fresh). Clears the cache for all sites in this network at once!', 'comet-cache'),
82
  'class' => '-wipe',
83
  'tabindex' => -1,
91
  [
92
  'parent' => 'top-secondary',
93
  'id' => GLOBAL_NS.'-clear',
94
+ 'title' => __('Clear Cache', 'comet-cache'),
95
+ 'href' => '#',
96
+ 'meta' => [
97
  'title' => is_multisite() && current_user_can($this->network_cap)
98
  ? __('Clear Cache (Start Fresh). Affects the current site only.', 'comet-cache')
99
  : '',
123
  'isMultisite' => is_multisite(),
124
  'currentUserHasCap' => current_user_can($this->cap),
125
  'currentUserHasNetworkCap' => current_user_can($this->network_cap),
126
+ 'htmlCompressorEnabled' => (bool) $this->options['htmlc_enable'],
127
  'ajaxURL' => site_url('/wp-load.php', is_ssl() ? 'https' : 'http'),
128
  'i18n' => [
129
  'name' => NAME,
171
  return; // Nothing to do.
172
  }
173
  $deps = ['jquery', 'admin-bar']; // Plugin dependencies.
174
+
175
+ if (IS_PRO && $this->adminBarShowing('stats')) {
176
  $deps[] = 'chartjs'; // Add ChartJS dependency.
177
  wp_enqueue_script('chartjs', set_url_scheme('//cdnjs.cloudflare.com/ajax/libs/Chart.js/1.0.2/Chart.min.js'), [], null, true);
178
  }
src/includes/traits/Plugin/InstallUtils.php CHANGED
@@ -19,6 +19,10 @@ trait InstallUtils
19
  if (defined('WP_CLI') && WP_CLI) {
20
  $this->updateOptions(['enable' => '1']);
21
  }
 
 
 
 
22
  if (!$this->options['welcomed'] && !$this->options['enable']) {
23
  $settings_url = add_query_arg(urlencode_deep(['page' => GLOBAL_NS]), network_admin_url('/admin.php'));
24
  $this->enqueueMainNotice(sprintf(__('<strong>%1$s</strong> successfully installed! :-) <strong>Please <a href="%2$s">enable caching and review options</a>.</strong>', 'comet-cache'), esc_html(NAME), esc_attr($settings_url)), ['push_to_top' => true]);
@@ -64,6 +68,10 @@ trait InstallUtils
64
  $this->wipeCache(); // Fresh start now.
65
 
66
  $this->enqueueMainNotice(sprintf(__('<strong>%1$s:</strong> detected a new version of itself. Recompiling w/ latest version... wiping the cache... all done :-)', 'comet-cache'), esc_html(NAME)), ['push_to_top' => true]);
 
 
 
 
67
  }
68
 
69
  /**
@@ -313,10 +321,11 @@ trait InstallUtils
313
  case 'exclude_hosts': // Converts to regex (caSe insensitive).
314
  case 'exclude_uris': // Converts to regex (caSe insensitive).
315
  case 'exclude_client_side_uris': // Converts to regex (caSe insensitive).
 
316
  case 'exclude_refs': // Converts to regex (caSe insensitive).
317
  case 'exclude_agents': // Converts to regex (caSe insensitive).
318
 
319
-
320
 
321
  $_value = "'".$this->escSq($this->lineDelimitedPatternsToRegex($_value))."'";
322
 
19
  if (defined('WP_CLI') && WP_CLI) {
20
  $this->updateOptions(['enable' => '1']);
21
  }
22
+ if (IS_PRO && (!$this->options['pro_update_username'] || !$this->options['pro_update_password'])) {
23
+ $configure_pro_updater_url = add_query_arg(urlencode_deep(['page' => GLOBAL_NS, GLOBAL_NS.'_configure_pro_updater' => 1]), network_admin_url('/admin.php')).'#'.SLUG_TD.'-configure-pro-updater';
24
+ $this->enqueueMainNotice('<form method="post" action="'.esc_url($configure_pro_updater_url).'" style="margin:.5em 0;">'.sprintf(__('<strong>IMPORTANT:</strong> To be notified when a new version of %1$s is available, please &nbsp; %2$s', 'comet-cache'), esc_html(NAME), '<button type="submit" class="button" style="vertical-align:middle;">'.__('Configure Pro Update Credentials', 'comet-cache').'</button>').'</form>', ['class' => 'notice notice-info', 'push_to_top' => true, 'persistent' => true, 'persistent_key' => 'configure-pro-updater', 'dismissable' => true]);
25
+ }
26
  if (!$this->options['welcomed'] && !$this->options['enable']) {
27
  $settings_url = add_query_arg(urlencode_deep(['page' => GLOBAL_NS]), network_admin_url('/admin.php'));
28
  $this->enqueueMainNotice(sprintf(__('<strong>%1$s</strong> successfully installed! :-) <strong>Please <a href="%2$s">enable caching and review options</a>.</strong>', 'comet-cache'), esc_html(NAME), esc_attr($settings_url)), ['push_to_top' => true]);
68
  $this->wipeCache(); // Fresh start now.
69
 
70
  $this->enqueueMainNotice(sprintf(__('<strong>%1$s:</strong> detected a new version of itself. Recompiling w/ latest version... wiping the cache... all done :-)', 'comet-cache'), esc_html(NAME)), ['push_to_top' => true]);
71
+
72
+ $this->dismissMainNotice('pro_update_error');
73
+ $this->dismissMainNotice('new-lite-version-available');
74
+ $this->dismissMainNotice('new-pro-version-available');
75
  }
76
 
77
  /**
321
  case 'exclude_hosts': // Converts to regex (caSe insensitive).
322
  case 'exclude_uris': // Converts to regex (caSe insensitive).
323
  case 'exclude_client_side_uris': // Converts to regex (caSe insensitive).
324
+ case 'ignore_get_request_vars': // Converts to regex (caSe insensitive).
325
  case 'exclude_refs': // Converts to regex (caSe insensitive).
326
  case 'exclude_agents': // Converts to regex (caSe insensitive).
327
 
328
+
329
 
330
  $_value = "'".$this->escSq($this->lineDelimitedPatternsToRegex($_value))."'";
331
 
src/includes/traits/Plugin/MenuPageUtils.php CHANGED
@@ -34,9 +34,12 @@ trait MenuPageUtils
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.
38
 
39
- wp_enqueue_script('chartjs', set_url_scheme('//cdnjs.cloudflare.com/ajax/libs/Chart.js/1.0.2/Chart.min.js'), [], null, true);
 
 
 
40
  wp_enqueue_script(GLOBAL_NS, $this->url('/src/client-s/js/menu-pages.min.js'), $deps, VERSION, true);
41
  wp_localize_script(
42
  GLOBAL_NS,
@@ -46,7 +49,7 @@ trait MenuPageUtils
46
  'isMultisite' => is_multisite(), // Network?
47
  'currentUserHasCap' => current_user_can($this->cap),
48
  'currentUserHasNetworkCap' => current_user_can($this->network_cap),
49
- 'htmlCompressorEnabled' => (boolean) $this->options['htmlc_enable'],
50
  'ajaxURL' => site_url('/wp-load.php', is_ssl() ? 'https' : 'http'),
51
  'emptyStatsCountsImageUrl' => $this->url('/src/client-s/images/stats-fc-empty.png'),
52
  'emptyStatsFilesImageUrl' => $this->url('/src/client-s/images/stats-fs-empty.png'),
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']; // Plugin dependencies.
38
 
39
+ if (IS_PRO) {
40
+ $deps[] = 'chartjs'; // Add ChartJS dependency.
41
+ wp_enqueue_script('chartjs', set_url_scheme('//cdnjs.cloudflare.com/ajax/libs/Chart.js/1.0.2/Chart.min.js'), [], null, true);
42
+ }
43
  wp_enqueue_script(GLOBAL_NS, $this->url('/src/client-s/js/menu-pages.min.js'), $deps, VERSION, true);
44
  wp_localize_script(
45
  GLOBAL_NS,
49
  'isMultisite' => is_multisite(), // Network?
50
  'currentUserHasCap' => current_user_can($this->cap),
51
  'currentUserHasNetworkCap' => current_user_can($this->network_cap),
52
+ 'htmlCompressorEnabled' => (bool) $this->options['htmlc_enable'],
53
  'ajaxURL' => site_url('/wp-load.php', is_ssl() ? 'https' : 'http'),
54
  'emptyStatsCountsImageUrl' => $this->url('/src/client-s/images/stats-fc-empty.png'),
55
  'emptyStatsFilesImageUrl' => $this->url('/src/client-s/images/stats-fs-empty.png'),
src/includes/traits/Plugin/NoticeUtils.php CHANGED
@@ -15,7 +15,7 @@ trait NoticeUtils
15
  * @since 150422 Rewrite. Improved 151002.
16
  *
17
  * @param string $notice HTML markup containing the notice itself.
18
- * @param array $args Any additional arguments supported by the notice API in this plugin.
19
  * @param int $blog_id Optional. Defaults to the current blog ID. Use any value `< 0` to indicate the main site.
20
  *
21
  * @return string A unique key generated for this notice.
@@ -23,7 +23,7 @@ trait NoticeUtils
23
  public function enqueueNotice($notice, array $args = [], $blog_id = 0)
24
  {
25
  $notice = trim((string) $notice);
26
- $blog_id = (integer) $blog_id;
27
 
28
  if (!$notice) {
29
  return; // Nothing to do.
@@ -58,7 +58,7 @@ trait NoticeUtils
58
  public function dismissNotice($key_to_dismiss, $blog_id = 0)
59
  {
60
  $key_to_dismiss = trim((string) $key_to_dismiss);
61
- $blog_id = (integer) $blog_id; // For multisite compat.
62
  $notices = $enqueued_notices = $this->getNotices($blog_id);
63
 
64
  if (!$key_to_dismiss) {
@@ -132,7 +132,7 @@ trait NoticeUtils
132
  */
133
  public function allAdminNotices()
134
  {
135
- $notices = $enqueued_notices = $this->getNotices();
136
  $combined_notices = []; // Initialize
137
 
138
  foreach ($notices as $_key => $_notice) {
@@ -166,9 +166,12 @@ trait NoticeUtils
166
  if ($_notice['combinable'] && !$_notice['persistent_key']) {
167
  $combined_notices[] = $_notice['notice']; // Save this for displaying as part of a single, combined notice.
168
  } else {
169
- echo '<div class="'.esc_attr($_notice['class']).'" style="clear:both; padding-right:38px; position: relative;"><p>'.$_notice['notice'].'</p>'.$_dismiss.'</div>';
 
 
 
 
170
  }
171
-
172
  if (!$_notice['persistent_key']) { // If not persistent, dismiss.
173
  unset($notices[$_key]); // Dismiss; this notice has been displayed now.
174
  }
@@ -180,13 +183,12 @@ trait NoticeUtils
180
  foreach ($combined_notices as $_item) {
181
  $_line_items .= '<p><span class="dashicons dashicons-yes"></span> '.$_item.'</p>'."\n";
182
  }
183
-
184
- $_show_details = __('Show details.', 'comet-cache');
185
  $_hide_details = __('Hide details.', 'comet-cache');
186
 
187
  $_combined = '<div class="updated notice is-dismissible" style="clear:both; padding-right:38px; position: relative;">';
188
  $_combined .= '<p><img src="'.esc_attr($this->url('/src/client-s/images/clear.png')).'" style="float:left; margin:0 10px 0 0; border:0;" />';
189
- $_combined .= sprintf(__('<strong>%1$s</strong> detected changes and intelligently cleared the cache to keep your site up-to-date. <a href="#" id="'.SLUG_TD.'-toggle-notices" onclick="jQuery(\'#'.SLUG_TD.'-combined-notices\').toggle();if (jQuery(\'#comet-cache-combined-notices\').is(\':visible\')) { jQuery(this).text(\''.$_hide_details.'\'); } else { jQuery(this).text(\''.$_show_details.'\'); }">'.$_show_details.'</a>', 'comet-cache'), esc_html(NAME)).'</p>';
190
  $_combined .= '<div id="'.SLUG_TD.'-combined-notices" style="display: none;">'.$_line_items.'</div>';
191
  $_combined .= '<button type="button" class="notice-dismiss"><span class="screen-reader-text">'.__('Dismiss this notice.', 'comet-cache').'</span></button>';
192
  $_combined .= '</div>';
@@ -195,7 +197,6 @@ trait NoticeUtils
195
 
196
  unset($_item, $_line_item, $_combined); // Housekeeping.
197
  }
198
-
199
  # Update notices if something changed above.
200
 
201
  if ($notices !== $enqueued_notices) { // Something changed?
@@ -220,11 +221,11 @@ trait NoticeUtils
220
  public function getNotices($blog_id = 0)
221
  {
222
  if (is_multisite()) {
223
- if (!($blog_id = (integer) $blog_id)) {
224
- $blog_id = (integer) get_current_blog_id();
225
  }
226
  if ($blog_id < 0) { // Blog for main site.
227
- $blog_id = (integer) get_current_site()->blog_id;
228
  }
229
  $blog_suffix = '_'.$blog_id; // Site option suffix.
230
  $notices = get_site_option(GLOBAL_NS.$blog_suffix.'_notices');
@@ -262,11 +263,11 @@ trait NoticeUtils
262
  public function updateNotices(array $notices, $blog_id = 0)
263
  {
264
  if (is_multisite()) {
265
- if (!($blog_id = (integer) $blog_id)) {
266
- $blog_id = (integer) get_current_blog_id();
267
  }
268
  if ($blog_id < 0) { // Blog for main site.
269
- $blog_id = (integer) get_current_site()->blog_id;
270
  }
271
  $blog_suffix = '_'.$blog_id; // Site option suffix.
272
  update_site_option(GLOBAL_NS.$blog_suffix.'_notices', $notices);
@@ -319,7 +320,7 @@ trait NoticeUtils
319
  case 'push_to_top':
320
  case 'combinable':
321
  case 'dismissable':
322
- $_value = (boolean) $_value;
323
  break; // Stop here.
324
 
325
  case 'class':
15
  * @since 150422 Rewrite. Improved 151002.
16
  *
17
  * @param string $notice HTML markup containing the notice itself.
18
+ * @param array $args Any additional arguments supported by the notice API in this plugin.
19
  * @param int $blog_id Optional. Defaults to the current blog ID. Use any value `< 0` to indicate the main site.
20
  *
21
  * @return string A unique key generated for this notice.
23
  public function enqueueNotice($notice, array $args = [], $blog_id = 0)
24
  {
25
  $notice = trim((string) $notice);
26
+ $blog_id = (int) $blog_id;
27
 
28
  if (!$notice) {
29
  return; // Nothing to do.
58
  public function dismissNotice($key_to_dismiss, $blog_id = 0)
59
  {
60
  $key_to_dismiss = trim((string) $key_to_dismiss);
61
+ $blog_id = (int) $blog_id; // For multisite compat.
62
  $notices = $enqueued_notices = $this->getNotices($blog_id);
63
 
64
  if (!$key_to_dismiss) {
132
  */
133
  public function allAdminNotices()
134
  {
135
+ $notices = $enqueued_notices = $this->getNotices();
136
  $combined_notices = []; // Initialize
137
 
138
  foreach ($notices as $_key => $_notice) {
166
  if ($_notice['combinable'] && !$_notice['persistent_key']) {
167
  $combined_notices[] = $_notice['notice']; // Save this for displaying as part of a single, combined notice.
168
  } else {
169
+ $_notice['notice'] = trim($_notice['notice']);
170
+ if (!preg_match('/^\<(?:p|div|form|h[1-6]|ul|ol)[\s>]/ui', $_notice['notice'])) {
171
+ $_notice['notice'] = '<p>'.$_notice['notice'].'</p>'; // Add `<p>` tag.
172
+ }
173
+ echo '<div class="'.esc_attr($_notice['class']).'" style="clear:both; padding-right:38px; position: relative;">'.$_notice['notice'].$_dismiss.'</div>';
174
  }
 
175
  if (!$_notice['persistent_key']) { // If not persistent, dismiss.
176
  unset($notices[$_key]); // Dismiss; this notice has been displayed now.
177
  }
183
  foreach ($combined_notices as $_item) {
184
  $_line_items .= '<p><span class="dashicons dashicons-yes"></span> '.$_item.'</p>'."\n";
185
  }
186
+ $_see_details = __('See details.', 'comet-cache');
 
187
  $_hide_details = __('Hide details.', 'comet-cache');
188
 
189
  $_combined = '<div class="updated notice is-dismissible" style="clear:both; padding-right:38px; position: relative;">';
190
  $_combined .= '<p><img src="'.esc_attr($this->url('/src/client-s/images/clear.png')).'" style="float:left; margin:0 10px 0 0; border:0;" />';
191
+ $_combined .= sprintf(__('<strong>%1$s</strong> detected changes and intelligently cleared the cache to keep your site up-to-date.', 'comet-cache'), esc_html(NAME)).' <a href="#" id="'.SLUG_TD.'-toggle-notices" style="text-decoration:none; border-bottom:1px dotted;" onclick="jQuery(\'#'.SLUG_TD.'-combined-notices\').toggle(); if (jQuery(\'#comet-cache-combined-notices\').is(\':visible\')) { jQuery(this).text(\''.$_hide_details.'\'); } else { jQuery(this).text(\''.$_see_details.'\'); }">'.$_see_details.'</a></p>';
192
  $_combined .= '<div id="'.SLUG_TD.'-combined-notices" style="display: none;">'.$_line_items.'</div>';
193
  $_combined .= '<button type="button" class="notice-dismiss"><span class="screen-reader-text">'.__('Dismiss this notice.', 'comet-cache').'</span></button>';
194
  $_combined .= '</div>';
197
 
198
  unset($_item, $_line_item, $_combined); // Housekeeping.
199
  }
 
200
  # Update notices if something changed above.
201
 
202
  if ($notices !== $enqueued_notices) { // Something changed?
221
  public function getNotices($blog_id = 0)
222
  {
223
  if (is_multisite()) {
224
+ if (!($blog_id = (int) $blog_id)) {
225
+ $blog_id = (int) get_current_blog_id();
226
  }
227
  if ($blog_id < 0) { // Blog for main site.
228
+ $blog_id = (int) get_current_site()->blog_id;
229
  }
230
  $blog_suffix = '_'.$blog_id; // Site option suffix.
231
  $notices = get_site_option(GLOBAL_NS.$blog_suffix.'_notices');
263
  public function updateNotices(array $notices, $blog_id = 0)
264
  {
265
  if (is_multisite()) {
266
+ if (!($blog_id = (int) $blog_id)) {
267
+ $blog_id = (int) get_current_blog_id();
268
  }
269
  if ($blog_id < 0) { // Blog for main site.
270
+ $blog_id = (int) get_current_site()->blog_id;
271
  }
272
  $blog_suffix = '_'.$blog_id; // Site option suffix.
273
  update_site_option(GLOBAL_NS.$blog_suffix.'_notices', $notices);
320
  case 'push_to_top':
321
  case 'combinable':
322
  case 'dismissable':
323
+ $_value = (bool) $_value;
324
  break; // Stop here.
325
 
326
  case 'class':
src/includes/traits/Plugin/OptionUtils.php CHANGED
@@ -10,8 +10,8 @@ trait OptionUtils
10
  *
11
  * @since 151002 Improving multisite compat.
12
  *
13
- * @param bool $intersect Discard options not present in $this->default_options
14
- * @param bool $refresh Force-pull options directly from get_site_option()
15
  *
16
  * @return array Plugin options.
17
  *
@@ -24,10 +24,10 @@ trait OptionUtils
24
  $options = []; // Force array.
25
  }
26
  if (!$options && is_array($zencache_options = get_site_option('zencache_options'))) {
27
- $options = $zencache_options; // Old ZenCache options.
28
- $options['crons_setup'] = $this->default_options['crons_setup'];
29
  $options['latest_lite_version'] = $this->default_options['latest_lite_version'];
30
- $options['latest_pro_version'] = $this->default_options['latest_pro_version'];
31
  }
32
  }
33
  $this->options = array_merge($this->default_options, $options);
@@ -51,7 +51,7 @@ trait OptionUtils
51
  *
52
  * @since 151002 Improving multisite compat.
53
  *
54
- * @param array $options One or more new options.
55
  * @param bool $intersect Discard options not present in $this->default_options
56
  *
57
  * @return array Plugin options after update.
@@ -66,6 +66,9 @@ trait OptionUtils
66
  if (!empty($options['base_dir']) && $options['base_dir'] !== $this->options['base_dir']) {
67
  $this->tryErasingAllFilesDirsIn($this->wpContentBaseDirTo(''));
68
  }
 
 
 
69
  $this->options = array_merge($this->default_options, $this->options, $options);
70
  $this->options = $intersect ? array_intersect_key($this->options, $this->default_options) : $this->options;
71
  update_site_option(GLOBAL_NS.'_options', $this->options);
10
  *
11
  * @since 151002 Improving multisite compat.
12
  *
13
+ * @param bool $intersect Discard options not present in $this->default_options
14
+ * @param bool $refresh Force-pull options directly from get_site_option()
15
  *
16
  * @return array Plugin options.
17
  *
24
  $options = []; // Force array.
25
  }
26
  if (!$options && is_array($zencache_options = get_site_option('zencache_options'))) {
27
+ $options = $zencache_options; // Old ZenCache options.
28
+ $options['crons_setup'] = $this->default_options['crons_setup'];
29
  $options['latest_lite_version'] = $this->default_options['latest_lite_version'];
30
+ $options['latest_pro_version'] = $this->default_options['latest_pro_version'];
31
  }
32
  }
33
  $this->options = array_merge($this->default_options, $options);
51
  *
52
  * @since 151002 Improving multisite compat.
53
  *
54
+ * @param array $options One or more new options.
55
  * @param bool $intersect Discard options not present in $this->default_options
56
  *
57
  * @return array Plugin options after update.
66
  if (!empty($options['base_dir']) && $options['base_dir'] !== $this->options['base_dir']) {
67
  $this->tryErasingAllFilesDirsIn($this->wpContentBaseDirTo(''));
68
  }
69
+ if (IS_PRO && !empty($options['pro_update_username']) && !empty($options['pro_update_password'])) {
70
+ $this->dismissMainNotice('configure-pro-updater');
71
+ }
72
  $this->options = array_merge($this->default_options, $this->options, $options);
73
  $this->options = $intersect ? array_intersect_key($this->options, $this->default_options) : $this->options;
74
  update_site_option(GLOBAL_NS.'_options', $this->options);
src/includes/traits/Plugin/WcpWooCommerceUtils.php CHANGED
@@ -27,4 +27,27 @@ trait WcpWooCommerceUtils
27
  $counter += $this->autoClearPostCache($product->id);
28
  }
29
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30
  }
27
  $counter += $this->autoClearPostCache($product->id);
28
  }
29
  }
30
+
31
+ /**
32
+ * Automatically clears cache file for a WooCommerce Product when its stock status is changed.
33
+ *
34
+ * @since 161119 Improving WooCommerce Compatibility.
35
+ *
36
+ * @attaches-to `woocommerce_product_set_stock_status` hook.
37
+ *
38
+ * @param string|int $product_id A WooCommerce product ID.
39
+ */
40
+ public function autoClearPostCacheOnWooCommerceSetStockStatus($product_id)
41
+ {
42
+ $counter = 0; // Initialize.
43
+
44
+ if (!is_null($done = &$this->cacheKey('autoClearPostCacheOnWooCommerceSetStockStatus'))) {
45
+ return $counter; // Already did this.
46
+ }
47
+ $done = true; // Flag as having been done.
48
+
49
+ if (class_exists('\\WooCommerce')) {
50
+ $counter += $this->autoClearPostCache($product_id);
51
+ }
52
+ }
53
  }
src/includes/traits/Shared/ArrayUtils.php ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace WebSharks\CometCache\Traits\Shared;
3
+
4
+ use WebSharks\CometCache\Classes;
5
+
6
+ trait ArrayUtils
7
+ {
8
+ /**
9
+ * Sorts by key.
10
+ *
11
+ * @since 161119 Array utils.
12
+ *
13
+ * @param array $array Input array.
14
+ * @param int $flags Defaults to `SORT_REGULAR`.
15
+ *
16
+ * @return array Output array.
17
+ */
18
+ public function ksortDeep($array, $flags = SORT_REGULAR)
19
+ {
20
+ $array = (array) $array;
21
+ $flags = (int) $flags;
22
+
23
+ ksort($array, $flags);
24
+
25
+ foreach ($array as $_key => &$_value) {
26
+ if (is_array($_value)) {
27
+ $_value = $this->ksortDeep($_value, $flags);
28
+ }
29
+ } // unset($_key, $_value); // Housekeeping.
30
+
31
+ return $array;
32
+ }
33
+ }
src/includes/traits/Shared/CachePathUtils.php CHANGED
@@ -5,6 +5,41 @@ use WebSharks\CometCache\Classes;
5
 
6
  trait CachePathUtils
7
  {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8
  /**
9
  * Cache-path suffix frag (regex).
10
  *
@@ -93,11 +128,8 @@ trait CachePathUtils
93
  $is_url_domain_mapped = $is_multisite && $can_consider_domain_mapping && $this->domainMappingBlogId($url);
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;
101
 
102
  # Build and return the cache path.
103
 
@@ -106,7 +138,6 @@ trait CachePathUtils
106
  }
107
  if (!($flags & $this::CACHE_PATH_NO_HOST)) {
108
  $cache_path .= $url_parts['host'].'/';
109
-
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 !== '/') {
@@ -145,15 +176,20 @@ trait CachePathUtils
145
  $cache_path .= 'index/';
146
  }
147
  }
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)) {
155
  if (isset($url_parts['query']) && $url_parts['query'] !== '') {
156
- $cache_path = rtrim($cache_path, '/').'.q/'.md5($url_parts['query']).'/';
 
 
 
 
 
 
 
 
157
  }
158
  }
159
  if (!($flags & $this::CACHE_PATH_NO_USER)) {
5
 
6
  trait CachePathUtils
7
  {
8
+ /**
9
+ * Filter query vars; e.g., remove those we ignore.
10
+ *
11
+ * @since 161119 Adding support for ignored GET vars.
12
+ * @since 161119 Adding support for sorted query vars.
13
+ *
14
+ * @param array $_vars Query vars to filter.
15
+ *
16
+ * @return array Filtered query vars.
17
+ */
18
+ public function filterQueryVars($_vars)
19
+ {
20
+ $_vars = (array) $_vars; // Force array.
21
+ $cache_key = $_vars === $_GET ? md5(serialize($_vars)) : '';
22
+
23
+ if ($cache_key && ($vars = &$this->staticKey(__FUNCTION__, $cache_key)) !== null) {
24
+ return $vars; // Already cached this.
25
+ }
26
+ $vars = $_vars; // Copy.
27
+ $short_name_lc = mb_strtolower(SHORT_NAME);
28
+ $ignore_get_request_vars_regex = defined('COMET_CACHE_IGNORE_GET_REQUEST_VARS') ? COMET_CACHE_IGNORE_GET_REQUEST_VARS : '';
29
+
30
+ foreach ($vars as $_key => $_value) {
31
+ if (!is_string($_key)) {
32
+ continue; // Not applicable.
33
+ } elseif ($_key === $short_name_lc.'AC' || $_key === $short_name_lc.'ABC') {
34
+ unset($vars[$_key]);
35
+ } elseif ($ignore_get_request_vars_regex && preg_match($ignore_get_request_vars_regex, $_key)) {
36
+ unset($vars[$_key]);
37
+ }
38
+ } // unset($_key, $_value); // Housekeeping.
39
+
40
+ return $vars = $vars ? $this->ksortDeep($vars) : [];
41
+ }
42
+
43
  /**
44
  * Cache-path suffix frag (regex).
45
  *
128
  $is_url_domain_mapped = $is_multisite && $can_consider_domain_mapping && $this->domainMappingBlogId($url);
129
  $host_base_dir_tokens = $this->hostBaseDirTokens(false, $is_url_domain_mapped, !empty($url_parts['path']) ? $url_parts['path'] : '/');
130
 
131
+ $is_a_multisite_base_dir = $is_multisite && $host_base_dir_tokens && $host_base_dir_tokens !== '/' && mb_stripos(!empty($url_parts['path']) ? rtrim($url_parts['path'], '/').'/' : '/', $host_base_dir_tokens) === 0;
132
+ $is_a_multisite_base_dir_root = $is_multisite && $is_a_multisite_base_dir && strcasecmp(trim($host_base_dir_tokens, '/'), trim(!empty($url_parts['path']) ? $url_parts['path'] : '/', '/')) === 0;
 
 
 
133
 
134
  # Build and return the cache path.
135
 
138
  }
139
  if (!($flags & $this::CACHE_PATH_NO_HOST)) {
140
  $cache_path .= $url_parts['host'].'/';
 
141
  // Put multisite sub-roots into a host directory of their own.
142
  // e.g., `example-com[[-base]-child1]` instead of `example-com`.
143
  if ($is_a_multisite_base_dir && $host_base_dir_tokens && $host_base_dir_tokens !== '/') {
176
  $cache_path .= 'index/';
177
  }
178
  }
 
 
 
179
  $cache_path = str_replace('.', '-', mb_strtolower($cache_path));
180
 
181
  if (!($flags & $this::CACHE_PATH_NO_QUV)) {
182
  if (!($flags & $this::CACHE_PATH_NO_QUERY)) {
183
  if (isset($url_parts['query']) && $url_parts['query'] !== '') {
184
+
185
+ // Support for ignored GET vars.
186
+ parse_str($url_parts['query'], $_query_vars);
187
+ $_query_vars = $this->filterQueryVars($_query_vars);
188
+ // ↑ Also sorts query vars for smarter caching.
189
+
190
+ if ($_query_vars) { // If we have cacheable query vars.
191
+ $cache_path = rtrim($cache_path, '/').'.q/'.md5(serialize($_query_vars)).'/';
192
+ } // unset($_query_vars); // Housekeeping.
193
  }
194
  }
195
  if (!($flags & $this::CACHE_PATH_NO_USER)) {
src/includes/traits/Shared/ConditionalUtils.php CHANGED
@@ -8,8 +8,8 @@ trait ConditionalUtils
8
  /**
9
  * PHP's language constructs.
10
  *
11
- * @type array PHP's language constructs.
12
- * Keys are currently unimportant. Subject to change.
13
  *
14
  * @since 160222 First documented version.
15
  */
@@ -36,7 +36,7 @@ trait ConditionalUtils
36
  *
37
  * @since 150821 Improving multisite compat.
38
  *
39
- * @return bool `TRUE` if this is the AdvancedCache class.
40
  */
41
  public function isAdvancedCache()
42
  {
@@ -48,7 +48,7 @@ trait ConditionalUtils
48
  *
49
  * @since 150821 Improving multisite compat.
50
  *
51
- * @return bool `TRUE` if this is the Plugin class.
52
  */
53
  public function isPlugin()
54
  {
@@ -56,101 +56,88 @@ trait ConditionalUtils
56
  }
57
 
58
  /**
59
- * Is the current request method `POST`, `PUT` or `DELETE`?
60
  *
61
  * @since 150422 Rewrite.
 
62
  *
63
- * @return bool `TRUE` if current request method is `POST`, `PUT` or `DELETE`.
64
- *
65
- * @note The return value of this function is cached to reduce overhead on repeat calls.
66
  */
67
  public function isPostPutDeleteRequest()
68
  {
69
- if (!is_null($is = &$this->staticKey('isPostPutDeleteRequest'))) {
70
  return $is; // Already cached this.
71
  }
72
  if (!empty($_POST)) {
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
  }
80
  return $is = false;
81
  }
82
 
83
  /**
84
- * Does the current request include an uncacheable query string?
85
- *
86
- * @since 151002 Improving Nginx support.
87
  *
88
- * @return bool True if request includes an uncacheable query string.
 
89
  *
90
- * @note The return value of this function is cached to reduce overhead on repeat calls.
91
  */
92
- public function requestContainsUncacheableQueryVars()
93
  {
94
- if (!is_null($is = &$this->staticKey('requestContainsUncacheableQueryVars'))) {
95
  return $is; // Already cached this.
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;
105
- }
106
  }
107
  return $is = false;
108
  }
109
 
110
  /**
111
- * Is the current request method is uncacheable?
112
- *
113
- * @since 150422 Rewrite.
114
  *
115
- * @return bool `TRUE` if current request method is uncacheable.
 
116
  *
117
- * @note The return value of this function is cached to reduce overhead on repeat calls.
118
  */
119
- public function isUncacheableRequestMethod()
120
  {
121
- if (!is_null($is = &$this->staticKey('isUncacheableRequestMethod'))) {
122
- return $is; // Already cached this.
123
  }
124
- if (!empty($_POST)) {
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
  }
132
- return $is = false;
133
  }
134
 
135
  /**
136
  * Should the current user should be considered a logged-in user?
137
  *
138
  * @since 150422 Rewrite.
 
139
  *
140
- * @return bool `TRUE` if current user should be considered a logged-in user.
141
- *
142
- * @note The return value of this function is cached to reduce overhead on repeat calls.
143
  */
144
  public function isLikeUserLoggedIn()
145
  {
146
- if (!is_null($is = &$this->staticKey('isLikeUserLoggedIn'))) {
147
  return $is; // Already cached this.
148
  }
149
  if (defined('SID') && SID) {
150
- return $is = true; // Session ID.
151
- }
152
- if (empty($_COOKIE)) {
153
- return $is = false; // No cookies.
154
  }
155
  $regex_logged_in_cookies = '/^'; // Initialize.
156
 
@@ -165,11 +152,13 @@ trait ConditionalUtils
165
  $regex_logged_in_cookies .= '/'; // Close regex.
166
 
167
  foreach ($_COOKIE as $_key => $_value) {
168
- if ($_value && preg_match($regex_logged_in_cookies, $_key)) {
 
 
 
169
  return $is = true; // Like a logged-in user.
170
  }
171
- }
172
- unset($_key, $_value); // Housekeeping.
173
 
174
  return $is = false;
175
  }
@@ -178,20 +167,18 @@ trait ConditionalUtils
178
  * Are we in a LOCALHOST environment?
179
  *
180
  * @since 150422 Rewrite.
 
181
  *
182
- * @return bool `TRUE` if we are in a LOCALHOST environment.
183
- *
184
- * @note The return value of this function is cached to reduce overhead on repeat calls.
185
  */
186
  public function isLocalhost()
187
  {
188
- if (!is_null($is = &$this->staticKey('isLocalhost'))) {
189
  return $is; // Already cached this.
190
  }
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;
@@ -203,23 +190,19 @@ trait ConditionalUtils
203
  * Is the current request for a feed?
204
  *
205
  * @since 150422 Rewrite.
 
206
  *
207
- * @return bool `TRUE` if the current request is for a feed.
208
- *
209
- * @note The return value of this function is cached to reduce overhead on repeat calls.
210
  */
211
  public function isFeed()
212
  {
213
- if (!is_null($is = &$this->staticKey('isFeed'))) {
214
  return $is; // Already cached this.
215
  }
216
  if (isset($_REQUEST['feed'])) {
217
  return $is = true;
218
- }
219
- if (!empty($_SERVER['REQUEST_URI']) && is_string($_SERVER['REQUEST_URI'])) {
220
- if (preg_match('/\/feed(?:[\/?]|$)/', $_SERVER['REQUEST_URI'])) {
221
- return $is = true;
222
- }
223
  }
224
  return $is = false;
225
  }
@@ -228,6 +211,7 @@ trait ConditionalUtils
228
  * Is a document/string an HTML/XML doc; or no?
229
  *
230
  * @since 150422 Rewrite.
 
231
  *
232
  * @param string $doc Input string/document to check.
233
  *
@@ -238,13 +222,10 @@ trait ConditionalUtils
238
  $doc = trim((string) $doc);
239
  $doc_hash = sha1($doc);
240
 
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;
@@ -254,28 +235,25 @@ trait ConditionalUtils
254
  * Does the current request have a cacheable content type?
255
  *
256
  * @since 150422 Rewrite.
 
257
  *
258
- * @return bool `TRUE` if the current request has a cacheable content type.
259
- *
260
- * @note The return value of this function is cached to reduce overhead on repeat calls.
261
  *
262
  * @warning Do NOT call upon this method until the end of a script execution.
263
  */
264
  public function hasACacheableContentType()
265
  {
266
- if (!is_null($is = &$this->staticKey('hasACacheableContentType'))) {
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
  }
281
  return $is = true;
@@ -285,31 +263,28 @@ trait ConditionalUtils
285
  * Does the current request have a cacheable HTTP status code?
286
  *
287
  * @since 150422 Rewrite.
 
288
  *
289
- * @return bool `TRUE` if the current request has a cacheable HTTP status code.
290
- *
291
- * @note The return value of this function is cached to reduce overhead on repeat calls.
292
  *
293
  * @warning Do NOT call upon this method until the end of a script execution.
294
  */
295
  public function hasACacheableStatus()
296
  {
297
- if (!is_null($is = &$this->staticKey('hasACacheableStatus'))) {
298
  return $is; // Already cached this.
299
  }
300
  if (($http_status = (string) $this->httpStatus()) && $http_status[0] !== '2' && $http_status !== '404') {
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
- ) {
308
- return $is = false; // Not a cacheable status.
309
- }
310
  }
311
- }
312
- unset($_key, $_header); // Housekeeping.
313
 
314
  return $is = true;
315
  }
@@ -318,43 +293,40 @@ trait ConditionalUtils
318
  * Checks if a PHP extension is loaded up.
319
  *
320
  * @since 150422 Rewrite.
 
321
  *
322
  * @param string $extension A PHP extension slug (i.e. extension name).
323
  *
324
- * @return bool `TRUE` if the extension is loaded.
325
- *
326
- * @note The return value of this function is cached to reduce overhead on repeat calls.
327
  */
328
  public function isExtensionLoaded($extension)
329
  {
330
  $extension = (string) $extension;
331
 
332
- if (!is_null($is = &$this->staticKey('isExtensionLoaded', $extension))) {
333
  return $is; // Already cached this.
334
  }
335
- return $is = (boolean) extension_loaded($extension);
336
  }
337
 
338
  /**
339
  * Is a particular function possible in every way?
340
  *
341
  * @since 150422 Rewrite.
 
342
  *
343
  * @param string $function A PHP function (or user function) to check.
344
  *
345
- * @return string `TRUE` if the function is possible.
346
- *
347
- * @note This checks (among other things) if the function exists and that it's callable.
348
- * It also checks the currently configured `disable_functions` and `suhosin.executor.func.blacklist`.
349
  */
350
  public function functionIsPossible($function)
351
  {
352
  $function = (string) $function;
353
 
354
- if (!is_null($is = &$this->staticKey('functionIsPossible', $function))) {
355
  return $is; // Already cached this.
356
  }
357
- if (is_null($disabled_functions = &$this->staticKey('functionIsPossible_disabled_functions'))) {
358
  $disabled_functions = []; // Initialize disabled/blacklisted functions.
359
 
360
  if (($disable_functions = trim(ini_get('disable_functions')))) {
@@ -368,10 +340,11 @@ trait ConditionalUtils
368
  }
369
  }
370
  if (!function_exists($function) || !is_callable($function)) {
371
- if (!in_array($function, $this->php_constructs, true)) { // A language construct
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
  }
8
  /**
9
  * PHP's language constructs.
10
  *
11
+ * @var array PHP's language constructs.
12
+ * @note Keys unimportant; subject to change.
13
  *
14
  * @since 160222 First documented version.
15
  */
36
  *
37
  * @since 150821 Improving multisite compat.
38
  *
39
+ * @return bool True if this is the AdvancedCache class.
40
  */
41
  public function isAdvancedCache()
42
  {
48
  *
49
  * @since 150821 Improving multisite compat.
50
  *
51
+ * @return bool True if this is the Plugin class.
52
  */
53
  public function isPlugin()
54
  {
56
  }
57
 
58
  /**
59
+ * `POST`, `PUT`, `DELETE`?
60
  *
61
  * @since 150422 Rewrite.
62
+ * @since 161119 Enhancements.
63
  *
64
+ * @return bool True if `POST`, `PUT`, `DELETE`.
 
 
65
  */
66
  public function isPostPutDeleteRequest()
67
  {
68
+ if (($is = &$this->staticKey(__FUNCTION__)) !== null) {
69
  return $is; // Already cached this.
70
  }
71
  if (!empty($_POST)) {
72
  return $is = true;
73
+ } elseif (!empty($_SERVER['REQUEST_METHOD']) && in_array(mb_strtoupper($_SERVER['REQUEST_METHOD']), ['POST', 'PUT', 'DELETE'], true)) {
74
+ return $is = true;
 
 
 
75
  }
76
  return $is = false;
77
  }
78
 
79
  /**
80
+ * Is the current request method is uncacheable?
 
 
81
  *
82
+ * @since 150422 Rewrite.
83
+ * @since 161119 Enhancements.
84
  *
85
+ * @return bool True if current request method is uncacheable.
86
  */
87
+ public function isUncacheableRequestMethod()
88
  {
89
+ if (($is = &$this->staticKey(__FUNCTION__)) !== null) {
90
  return $is; // Already cached this.
91
  }
92
+ if (!empty($_POST)) {
93
+ return $is = true;
94
+ } elseif (!empty($_SERVER['REQUEST_METHOD']) && mb_strtoupper($_SERVER['REQUEST_METHOD']) !== 'GET') {
95
+ return $is = true;
 
 
 
 
 
96
  }
97
  return $is = false;
98
  }
99
 
100
  /**
101
+ * Does the current request include an uncacheable query string?
 
 
102
  *
103
+ * @since 151002 Improving Nginx support.
104
+ * @since 161119 Adding support for ignored GET vars.
105
  *
106
+ * @return bool True if request includes an uncacheable query string.
107
  */
108
+ public function requestContainsUncacheableQueryVars()
109
  {
110
+ if (($contains = &$this->staticKey(__FUNCTION__)) !== null) {
111
+ return $contains; // Already cached this.
112
  }
113
+ if (!$_GET) { // No GET vars whatsoever?
114
+ return $contains = false; // Nothing to check.
115
  }
116
+ $short_name_lc = mb_strtolower(SHORT_NAME); // Needed below.
117
+
118
+ if (isset($_GET[$short_name_lc.'AC']) && filter_var($_GET[$short_name_lc.'AC'], FILTER_VALIDATE_BOOLEAN)) {
119
+ return $contains = false; // `?ccAC` allows caching.
120
  }
121
+ return $contains = $this->filterQueryVars($_GET) ? true : false;
122
  }
123
 
124
  /**
125
  * Should the current user should be considered a logged-in user?
126
  *
127
  * @since 150422 Rewrite.
128
+ * @since 161119 Enhancements.
129
  *
130
+ * @return bool True if current user should be considered a logged-in user.
 
 
131
  */
132
  public function isLikeUserLoggedIn()
133
  {
134
+ if (($is = &$this->staticKey(__FUNCTION__)) !== null) {
135
  return $is; // Already cached this.
136
  }
137
  if (defined('SID') && SID) {
138
+ return $is = true;
139
+ } elseif (empty($_COOKIE)) {
140
+ return $is = false;
 
141
  }
142
  $regex_logged_in_cookies = '/^'; // Initialize.
143
 
152
  $regex_logged_in_cookies .= '/'; // Close regex.
153
 
154
  foreach ($_COOKIE as $_key => $_value) {
155
+ $_key = (string) $_key;
156
+ $_value = (string) $_value;
157
+
158
+ if (isset($_value[0]) && preg_match($regex_logged_in_cookies, $_key)) {
159
  return $is = true; // Like a logged-in user.
160
  }
161
+ } // unset($_key, $_value); // Housekeeping.
 
162
 
163
  return $is = false;
164
  }
167
  * Are we in a LOCALHOST environment?
168
  *
169
  * @since 150422 Rewrite.
170
+ * @since 161119 Enhancements.
171
  *
172
+ * @return bool True if we are in a LOCALHOST environment.
 
 
173
  */
174
  public function isLocalhost()
175
  {
176
+ if (($is = &$this->staticKey(__FUNCTION__)) !== null) {
177
  return $is; // Already cached this.
178
  }
179
  if (defined('LOCALHOST')) {
180
+ return $is = (bool) LOCALHOST;
181
+ } elseif (preg_match('/\b(?:localhost|127\.0\.0\.1)\b/ui', $this->hostToken())) {
 
182
  return $is = true;
183
  }
184
  return $is = false;
190
  * Is the current request for a feed?
191
  *
192
  * @since 150422 Rewrite.
193
+ * @since 161119 Enhancements.
194
  *
195
+ * @return bool True if the current request is for a feed.
 
 
196
  */
197
  public function isFeed()
198
  {
199
+ if (($is = &$this->staticKey(__FUNCTION__)) !== null) {
200
  return $is; // Already cached this.
201
  }
202
  if (isset($_REQUEST['feed'])) {
203
  return $is = true;
204
+ } elseif (!empty($_SERVER['REQUEST_URI']) && preg_match('/\/feed(?:[\/?]|$)/', $_SERVER['REQUEST_URI'])) {
205
+ return $is = true;
 
 
 
206
  }
207
  return $is = false;
208
  }
211
  * Is a document/string an HTML/XML doc; or no?
212
  *
213
  * @since 150422 Rewrite.
214
+ * @since 161119 Enhancements.
215
  *
216
  * @param string $doc Input string/document to check.
217
  *
222
  $doc = trim((string) $doc);
223
  $doc_hash = sha1($doc);
224
 
225
+ if (($is = &$this->staticKey(__FUNCTION__, $doc_hash)) !== null) {
226
  return $is; // Already cached this.
227
  }
228
+ if (mb_stripos($doc, '</html>') !== false || mb_stripos($doc, '<?xml') === 0) {
 
 
 
229
  return $is = true;
230
  }
231
  return $is = false;
235
  * Does the current request have a cacheable content type?
236
  *
237
  * @since 150422 Rewrite.
238
+ * @since 161119 Enhancements.
239
  *
240
+ * @return bool True if the current request has a cacheable content type.
 
 
241
  *
242
  * @warning Do NOT call upon this method until the end of a script execution.
243
  */
244
  public function hasACacheableContentType()
245
  {
246
+ if (($is = &$this->staticKey(__FUNCTION__)) !== null) {
247
  return $is; // Already cached this.
248
  }
249
  foreach ($this->headersList() as $_key => $_header) {
250
+ if (mb_stripos($_header, 'content-type:') === 0) {
251
+ $content_type = $_header;
252
+ } // Use last content-type header.
253
+ } // unset($_key, $_header); // Housekeeping.
 
254
 
255
  if (isset($content_type[0]) && mb_stripos($content_type, 'html') === false
256
+ && mb_stripos($content_type, 'xml') === false && mb_stripos($content_type, GLOBAL_NS) === false) {
 
257
  return $is = false; // Do NOT cache data sent by scripts serving other MIME types.
258
  }
259
  return $is = true;
263
  * Does the current request have a cacheable HTTP status code?
264
  *
265
  * @since 150422 Rewrite.
266
+ * @since 161119 Enhancements.
267
  *
268
+ * @return bool True if the current request has a cacheable HTTP status code.
 
 
269
  *
270
  * @warning Do NOT call upon this method until the end of a script execution.
271
  */
272
  public function hasACacheableStatus()
273
  {
274
+ if (($is = &$this->staticKey(__FUNCTION__)) !== null) {
275
  return $is; // Already cached this.
276
  }
277
  if (($http_status = (string) $this->httpStatus()) && $http_status[0] !== '2' && $http_status !== '404') {
278
  return $is = false; // A non-2xx & non-404 status code.
279
  }
280
  foreach ($this->headersList() as $_key => $_header) {
281
+ 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)) {
282
+ continue; // Not applicable; i.e., Not a header that is worth checking here.
283
+ } elseif (!empty($_m['retry']) || (!empty($_m['status']) && $_m['status'][0] !== '2' && $_m['status'] !== '404')
284
+ || (!empty($_m['http_status']) && $_m['http_status'][0] !== '2' && $_m['http_status'] !== '404')) {
285
+ return $is = false; // Not a cacheable status.
 
286
  }
287
+ } // unset($_key, $_header, $_m); // Housekeeping.
 
288
 
289
  return $is = true;
290
  }
293
  * Checks if a PHP extension is loaded up.
294
  *
295
  * @since 150422 Rewrite.
296
+ * @since 161119 Enhancements.
297
  *
298
  * @param string $extension A PHP extension slug (i.e. extension name).
299
  *
300
+ * @return bool True if the extension is loaded.
 
 
301
  */
302
  public function isExtensionLoaded($extension)
303
  {
304
  $extension = (string) $extension;
305
 
306
+ if (($is = &$this->staticKey(__FUNCTION__, $extension)) !== null) {
307
  return $is; // Already cached this.
308
  }
309
+ return $is = (bool) extension_loaded($extension);
310
  }
311
 
312
  /**
313
  * Is a particular function possible in every way?
314
  *
315
  * @since 150422 Rewrite.
316
+ * @since 161119 Enhancements.
317
  *
318
  * @param string $function A PHP function (or user function) to check.
319
  *
320
+ * @return string True if the function is possible.
 
 
 
321
  */
322
  public function functionIsPossible($function)
323
  {
324
  $function = (string) $function;
325
 
326
+ if (($is = &$this->staticKey(__FUNCTION__, $function)) !== null) {
327
  return $is; // Already cached this.
328
  }
329
+ if (($disabled_functions = &$this->staticKey(__FUNCTION__.'_disabled_functions')) === null) {
330
  $disabled_functions = []; // Initialize disabled/blacklisted functions.
331
 
332
  if (($disable_functions = trim(ini_get('disable_functions')))) {
340
  }
341
  }
342
  if (!function_exists($function) || !is_callable($function)) {
343
+ if (!in_array($function, $this->php_constructs, true)) {
344
  return $is = false; // Not possible.
345
  }
346
+ } // In PHP, language constructs cannot be disabled/blacklisted whatsoever.
347
+
348
  if ($disabled_functions && in_array(mb_strtolower($function), $disabled_functions, true)) {
349
  return $is = false; // Not possible.
350
  }
src/includes/traits/Shared/StringUtils.php CHANGED
@@ -91,4 +91,58 @@ trait StringUtils
91
 
92
  return $string;
93
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
94
  }
91
 
92
  return $string;
93
  }
94
+
95
+ /**
96
+ * Multibyte `str_pad()`.
97
+ *
98
+ * @since 161119 Enhancing multibyte support.
99
+ *
100
+ * @param mixed $value Any input value.
101
+ * @param int $pad_length The required length of the string.
102
+ * @param string $pad_string The string to pad with.
103
+ * @param int $pad_type `STR_PAD_LEFT`, `STR_PAD_RIGHT`, `STR_PAD_BOTH`.
104
+ *
105
+ * @throws \Exception if unexpected `pad_type`
106
+ *
107
+ * @return string|array|object Output value.
108
+ */
109
+ public function strPad($value, $pad_length, $pad_string = ' ', $pad_type = STR_PAD_RIGHT)
110
+ {
111
+ if (is_array($value) || is_object($value)) {
112
+ foreach ($value as $_key => &$_value) {
113
+ $_value = $this->strPad($_value, $pad_length, $pad_string, $pad_type);
114
+ } // unset($_key, $_value);
115
+ return $value;
116
+ }
117
+ $string = (string) $value;
118
+ $pad_length = (int) $pad_length;
119
+ $pad_string = (string) $pad_string;
120
+ $mb_strlen = mb_strlen($string);
121
+
122
+ if ($pad_length < 0 || $pad_length <= $mb_strlen) {
123
+ return $string; // Nothing to do.
124
+ }
125
+ $pad_string_mb_strlen = mb_strlen($pad_string);
126
+
127
+ switch ($pad_type) {
128
+ case STR_PAD_LEFT:
129
+ $repeat = (int) ceil(max(0, $mb_strlen - $pad_string_mb_strlen) + $pad_length);
130
+ $string = str_repeat($pad_string, $repeat).$string;
131
+ return mb_substr($string, -$pad_length);
132
+
133
+ case STR_PAD_RIGHT:
134
+ $repeat = (int) ceil(max(0, $mb_strlen - $pad_string_mb_strlen) + $pad_length);
135
+ $string = $string.str_repeat($pad_string, $repeat);
136
+ return mb_substr($string, 0, $pad_length);
137
+
138
+ case STR_PAD_BOTH:
139
+ $half_pad_length = ($pad_length - $mb_strlen) / 2;
140
+ $split_repeat = (int) ceil($pad_length / $pad_string_mb_strlen);
141
+ return mb_substr(str_repeat($pad_string, $split_repeat), 0, (int) floor($half_pad_length))
142
+ .$string.mb_substr(str_repeat($pad_string, $split_repeat), 0, (int) ceil($half_pad_length));
143
+
144
+ default: // Exception on unexpected pad type.
145
+ throw new \Exception(__('Unexpected `pad_type`.', 'comet-cache'));
146
+ }
147
+ }
148
  }
src/vendor/autoload.php CHANGED
@@ -4,4 +4,4 @@
4
 
5
  require_once __DIR__ . '/composer' . '/autoload_real.php';
6
 
7
- return ComposerAutoloaderInit62f8f3ca78045447be6889b49666f4b3::getLoader();
4
 
5
  require_once __DIR__ . '/composer' . '/autoload_real.php';
6
 
7
+ return ComposerAutoloaderInite04c11378fd6d65cfa7ace2de8ffa898::getLoader();
src/vendor/composer/autoload_classmap.php CHANGED
@@ -16,6 +16,7 @@ return array(
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',
@@ -59,6 +60,7 @@ return array(
59
  'WebSharks\\CometCache\\Traits\\Plugin\\WcpUpdaterUtils' => $baseDir . '/src/includes/traits/Plugin/WcpUpdaterUtils.php',
60
  'WebSharks\\CometCache\\Traits\\Plugin\\WcpUtils' => $baseDir . '/src/includes/traits/Plugin/WcpUtils.php',
61
  'WebSharks\\CometCache\\Traits\\Plugin\\WcpWooCommerceUtils' => $baseDir . '/src/includes/traits/Plugin/WcpWooCommerceUtils.php',
 
62
  'WebSharks\\CometCache\\Traits\\Shared\\BlogUtils' => $baseDir . '/src/includes/traits/Shared/BlogUtils.php',
63
  'WebSharks\\CometCache\\Traits\\Shared\\CacheDirUtils' => $baseDir . '/src/includes/traits/Shared/CacheDirUtils.php',
64
  'WebSharks\\CometCache\\Traits\\Shared\\CacheLockUtils' => $baseDir . '/src/includes/traits/Shared/CacheLockUtils.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\\Notes' => $baseDir . '/src/includes/classes/Notes.php',
20
  'WebSharks\\CometCache\\Classes\\Plugin' => $baseDir . '/src/includes/classes/Plugin.php',
21
  'WebSharks\\CometCache\\Classes\\VsUpgrades' => $baseDir . '/src/includes/classes/VsUpgrades.php',
22
  'WebSharks\\CometCache\\Interfaces\\Shared\\CachePathConsts' => $baseDir . '/src/includes/interfaces/Shared/CachePathConsts.php',
60
  'WebSharks\\CometCache\\Traits\\Plugin\\WcpUpdaterUtils' => $baseDir . '/src/includes/traits/Plugin/WcpUpdaterUtils.php',
61
  'WebSharks\\CometCache\\Traits\\Plugin\\WcpUtils' => $baseDir . '/src/includes/traits/Plugin/WcpUtils.php',
62
  'WebSharks\\CometCache\\Traits\\Plugin\\WcpWooCommerceUtils' => $baseDir . '/src/includes/traits/Plugin/WcpWooCommerceUtils.php',
63
+ 'WebSharks\\CometCache\\Traits\\Shared\\ArrayUtils' => $baseDir . '/src/includes/traits/Shared/ArrayUtils.php',
64
  'WebSharks\\CometCache\\Traits\\Shared\\BlogUtils' => $baseDir . '/src/includes/traits/Shared/BlogUtils.php',
65
  'WebSharks\\CometCache\\Traits\\Shared\\CacheDirUtils' => $baseDir . '/src/includes/traits/Shared/CacheDirUtils.php',
66
  'WebSharks\\CometCache\\Traits\\Shared\\CacheLockUtils' => $baseDir . '/src/includes/traits/Shared/CacheLockUtils.php',
src/vendor/composer/autoload_real.php CHANGED
@@ -2,7 +2,7 @@
2
 
3
  // autoload_real.php @generated by Composer
4
 
5
- class ComposerAutoloaderInit62f8f3ca78045447be6889b49666f4b3
6
  {
7
  private static $loader;
8
 
@@ -19,9 +19,9 @@ class ComposerAutoloaderInit62f8f3ca78045447be6889b49666f4b3
19
  return self::$loader;
20
  }
21
 
22
- spl_autoload_register(array('ComposerAutoloaderInit62f8f3ca78045447be6889b49666f4b3', 'loadClassLoader'), true, true);
23
  self::$loader = $loader = new \Composer\Autoload\ClassLoader();
24
- spl_autoload_unregister(array('ComposerAutoloaderInit62f8f3ca78045447be6889b49666f4b3', '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 ComposerAutoloaderInite04c11378fd6d65cfa7ace2de8ffa898
6
  {
7
  private static $loader;
8
 
19
  return self::$loader;
20
  }
21
 
22
+ spl_autoload_register(array('ComposerAutoloaderInite04c11378fd6d65cfa7ace2de8ffa898', 'loadClassLoader'), true, true);
23
  self::$loader = $loader = new \Composer\Autoload\ClassLoader();
24
+ spl_autoload_unregister(array('ComposerAutoloaderInite04c11378fd6d65cfa7ace2de8ffa898', 'loadClassLoader'));
25
 
26
  $map = require __DIR__ . '/autoload_namespaces.php';
27
  foreach ($map as $namespace => $path) {
src/vendor/composer/installed.json CHANGED
@@ -114,17 +114,17 @@
114
  },
115
  {
116
  "name": "websharks/html-compressor",
117
- "version": "160118",
118
- "version_normalized": "160118",
119
  "source": {
120
  "type": "git",
121
  "url": "https://github.com/websharks/html-compressor.git",
122
- "reference": "bd1ba2407b9c2c067549600a6ef1faa726c3c2d2"
123
  },
124
  "dist": {
125
  "type": "zip",
126
- "url": "https://api.github.com/repos/websharks/html-compressor/zipball/bd1ba2407b9c2c067549600a6ef1faa726c3c2d2",
127
- "reference": "bd1ba2407b9c2c067549600a6ef1faa726c3c2d2",
128
  "shasum": ""
129
  },
130
  "require": {
@@ -135,7 +135,7 @@
135
  "websharks/css-minifier": "dev-master",
136
  "websharks/js-minifier": "dev-master"
137
  },
138
- "time": "2016-01-18 03:17:20",
139
  "type": "library",
140
  "installation-source": "dist",
141
  "autoload": {
114
  },
115
  {
116
  "name": "websharks/html-compressor",
117
+ "version": "161108",
118
+ "version_normalized": "161108",
119
  "source": {
120
  "type": "git",
121
  "url": "https://github.com/websharks/html-compressor.git",
122
+ "reference": "73a047734ab585cfaaa3e54526a484b788d768f5"
123
  },
124
  "dist": {
125
  "type": "zip",
126
+ "url": "https://api.github.com/repos/websharks/html-compressor/zipball/73a047734ab585cfaaa3e54526a484b788d768f5",
127
+ "reference": "73a047734ab585cfaaa3e54526a484b788d768f5",
128
  "shasum": ""
129
  },
130
  "require": {
135
  "websharks/css-minifier": "dev-master",
136
  "websharks/js-minifier": "dev-master"
137
  },
138
+ "time": "2016-11-08 20:56:04",
139
  "type": "library",
140
  "installation-source": "dist",
141
  "autoload": {
src/vendor/websharks/sharkicons/README.md ADDED
@@ -0,0 +1,154 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ## WebSharks™ Icon Font (Sharkicons)
2
+
3
+ Font containing WebSharks logos/icons + many others; including FontAwesome! See: [**DEMO**](http://websharks.github.io/sharkicons/demo.html)
4
+
5
+ _Contains over 750 icons. Total file size: 212kb (compare to stand-alone FontAwesome @ 136kb)._
6
+
7
+ [![](https://img.shields.io/github/license/websharks/sharkicons.svg)](https://github.com/websharks/sharkicons/blob/HEAD/LICENSE.txt)
8
+ [![](https://img.shields.io/badge/made-w%2F_100%25_pure_awesome_sauce-AB815F.svg?label=made)](http://websharks-inc.com/)
9
+ [![](https://img.shields.io/badge/by-WebSharks_Inc.-656598.svg?label=by)](http://www.websharks-inc.com/team/)
10
+ [![](https://img.shields.io/github/release/websharks/sharkicons.svg?label=latest)](https://github.com/websharks/sharkicons/releases)
11
+ [![](https://img.shields.io/packagist/v/websharks/sharkicons.svg?label=packagist)](https://packagist.org/packages/websharks/sharkicons)
12
+ [![](https://img.shields.io/github/issues/websharks/sharkicons.svg?label=issues)](https://github.com/websharks/sharkicons/issues)
13
+ [![](https://img.shields.io/github/forks/websharks/sharkicons.svg?label=forks)](https://github.com/websharks/sharkicons/network)
14
+ [![](https://img.shields.io/github/stars/websharks/sharkicons.svg?label=stars)](https://github.com/websharks/sharkicons/stargazers)
15
+ [![](https://img.shields.io/github/downloads/websharks/sharkicons/latest/total.svg?label=downloads)](https://github.com/websharks/sharkicons/releases)
16
+ [![](https://img.shields.io/packagist/dt/websharks/sharkicons.svg?label=packagist)](https://packagist.org/packages/websharks/sharkicons)
17
+
18
+ ---
19
+
20
+ ![](assets/screenshot.png)
21
+
22
+ ---
23
+
24
+ ## Using Icons in HTML Markup
25
+
26
+ ```html
27
+ <link rel="stylesheet" type="text/css" href="/path/to/sharkicons/src/long-classes.min.css" />
28
+ ```
29
+
30
+ ```html
31
+ <i class="sharkicon sharkicon-broom"></i>
32
+ ```
33
+
34
+ ---
35
+
36
+ ## Short Classes (`si-` instead of `sharkicon-`)
37
+
38
+ ```html
39
+ <link rel="stylesheet" type="text/css" href="/path/to/sharkicons/src/short-classes.min.css" />
40
+ ```
41
+
42
+ ```html
43
+ <i class="si si-broom"></i>
44
+ ```
45
+
46
+ ---
47
+
48
+ ## Including Classes via SCSS
49
+
50
+ _**Note:** Bourbon is a required dependency. See: <http://bourbon.io/> for details._
51
+
52
+ ```scss
53
+ @import '/path/to/bourbon';
54
+ @import '/path/to/sharkicons/src/sharkicons';
55
+ @include sharkicons-font('/path/to/sharkicons/src');
56
+ @include sharkicon-short-classes;
57
+ ```
58
+
59
+ ---
60
+
61
+ ## Custom Classes via SCSS (`prefix` instead of `si`)
62
+
63
+ ```scss
64
+ @import '/path/to/bourbon';
65
+ @import '/path/to/sharkicons/src/sharkicons';
66
+ @include sharkicons-font('/path/to/sharkicons/src');
67
+ @include sharkicon-custom-classes(prefix);
68
+ ```
69
+
70
+ ---
71
+
72
+ ## Scoping Classes via SCSS
73
+
74
+ ```scss
75
+ @import '/path/to/bourbon';
76
+ @import '/path/to/sharkicons/src/sharkicons';
77
+ @include sharkicons-font('/path/to/sharkicons/src');
78
+
79
+ .my-product {
80
+ @include sharkicon-short-classes;
81
+ }
82
+ ```
83
+
84
+ ---
85
+
86
+ ## Creating an Icon via SCSS
87
+
88
+ _Note: you can do this without including the `sharkicon-[long|short]-classes` if you like._
89
+
90
+ ```scss
91
+ @import '/path/to/bourbon';
92
+ @import '/path/to/sharkicons/src/sharkicons';
93
+ @include sharkicons-font('/path/to/sharkicons/src');
94
+ // @include sharkicon-short-classes;
95
+
96
+ .my-product .my-icon {
97
+ @include sharkicon(broom);
98
+ }
99
+ ```
100
+
101
+ Equivalent to:
102
+
103
+ ```css
104
+ .my-product .my-icon::before {
105
+ content: '\e000';
106
+ font: normal normal normal 14px/1 sharkicons;
107
+ text-rendering: optimizeLegibility;
108
+ -webkit-font-smoothing: antialiased;
109
+ font-smoothing: antialiased;
110
+ display: inline-block;
111
+ font-size: inherit;
112
+ text-decoration: inherit;
113
+ text-transform: none;
114
+ }
115
+ ```
116
+
117
+ Alternatively, you can pass a second argument to `sharkicon()` to set the before/after specification. The default value is `before`. You might want to change it to `after` in some special case.
118
+
119
+ ```scss
120
+ @import '/path/to/bourbon';
121
+ @import '/path/to/sharkicons/src/sharkicons';
122
+ @include sharkicons-font('/path/to/sharkicons/src');
123
+ // @include sharkicon-short-classes;
124
+
125
+ .my-product .my-icon {
126
+ @include sharkicon(broom, after);
127
+ }
128
+ ```
129
+
130
+ Equivalent to:
131
+
132
+ ```css
133
+ .my-product .my-icon::after {
134
+ content: '\e000';
135
+ font: normal normal normal 14px/1 sharkicons;
136
+ text-rendering: optimizeLegibility;
137
+ -webkit-font-smoothing: antialiased;
138
+ font-smoothing: antialiased;
139
+ display: inline-block;
140
+ font-size: inherit;
141
+ text-decoration: inherit;
142
+ text-transform: none;
143
+ }
144
+ ```
145
+
146
+ ---
147
+
148
+ ## Mapping An Icon Char via SCSS
149
+
150
+ ```scss
151
+ .my-product .my-icon:hover::after {
152
+ content: map-get($sharkicons, broom);
153
+ }
154
+ ```
src/vendor/websharks/wp-php-rv/README.md ADDED
@@ -0,0 +1,124 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ## WP PHP vX.x+ (Version Check w/ Dashboard Notice)
2
+
3
+ Stub for WordPress themes/plugins that require PHP vX.x+ (i.e. a minimum version that you define).
4
+
5
+ ![](assets/screenshot.png)
6
+
7
+ ---
8
+
9
+ ### Example Usage in a Typical WordPress Theme/Plugin File
10
+
11
+ ```php
12
+ <?php
13
+ /*
14
+ Plugin Name: My Plugin
15
+ Plugin URI: http://example.com/my-plugin
16
+ Description: Example plugin.
17
+ Author: Example Author.
18
+ Version: 0.1-alpha
19
+ Author URI: http://example.com
20
+ Text Domain: my-plugin
21
+ */
22
+ $GLOBALS['wp_php_rv'] = '5.3'; // Require PHP vX.x+ (you configure this).
23
+ if(require('wp-php-rv/src/includes/check.php')) // `true` if running PHP vX.x+.
24
+ require dirname(__FILE__).'/my-plugin-code.php'; // It's OK to load your plugin.
25
+ else wp_php_rv_notice(); // Creates a nice PHP vX.x+ dashboard notice for the site owner.
26
+ ```
27
+
28
+ ---
29
+
30
+ ### Alternate Approach
31
+
32
+ The `check.php` file will automatically return `true` upon using `include()` or `require()` in your scripts; i.e., iff the installation site is running PHP vX.x+ (as configured by `$GLOBALS['wp_php_rv']`). Otherwise it returns `false`. Therefore, the simplest way to run your check is to use `if(require('wp-php-rv/src/includes/check.php'))`. **However**, you could also choose to do it this way.
33
+
34
+ ```php
35
+ <?php
36
+ $GLOBALS['wp_php_rv'] = '5.3'; // Require PHP vX.x+.
37
+ require 'wp-php-rv/src/includes/check.php'; // Include.
38
+
39
+ if(wp_php_rv()) // `true` if running PHP vX.x+.
40
+ require dirname(__FILE__).'/my-plugin-code.php'; // It's OK to load your plugin.
41
+ else wp_php_rv_notice(); // Creates a nice PHP vX.x+ dashboard notice for the site owner.
42
+ ```
43
+
44
+ ---
45
+
46
+ ### Dashboard Notice that Calls your Software by Name
47
+
48
+ ```php
49
+ <?php
50
+ $GLOBALS['wp_php_rv'] = '5.3'; // Require PHP vX.x+.
51
+ if(require('wp-php-rv/src/includes/check.php')) // `true` if running PHP vX.x+.
52
+ require dirname(__FILE__).'/my-plugin-code.php'; // It's OK to load your plugin.
53
+ else wp_php_rv_notice('My Plugin'); // Dashboard notice mentions your software specifically.
54
+ ```
55
+
56
+ **Note:** If you omit the `$brand_name` argument, a default value is used instead. The default value is `ucwords('[calling file basedir]')`; e.g., if `/my-plugin/stub.php` calls `wp-php-rv/src/includes/check.php`, the default `$software_name` automatically becomes `My Plugin`. Nice!
57
+
58
+ ---
59
+
60
+ ### What if multiple themes/plugins use this?
61
+
62
+ This is fine! :-) The `wp-php-rv/src/includes/check.php` file uses `function_exists()` as a wrapper; which allows it to be included any number of times, and by any number of plugins; and also from any number of locations. **The only thing to remember**, is that you MUST be sure to define `$GLOBALS['wp_php_rv']` each time; i.e., each time you `include('wp-php-rv/src/includes/check.php')` or `require('wp-php-rv/src/includes/check.php')`.
63
+
64
+ The point here, is that `$GLOBALS['wp_php_rv']` defines a PHP version that is specific to your plugin requirements, so it should be defined explicitly by each plugin developer before they `include('wp-php-rv/src/includes/check.php')` or `require('wp-php-rv/src/includes/check.php')`.
65
+
66
+ ---
67
+
68
+ ### Can this just go at the top of my existing theme/plugin file?
69
+
70
+ **No, there are two important things to remember.**
71
+
72
+ 1. Don't forget to bundle a copy of the `websharks/wp-php-rv` repo with your theme/plugin. All you really need is the `/src` directory.
73
+ 2. Don't leave your existing code in the same file. Use this in a stub file that checks for PHP vX.x+ first (as seen in the examples above), BEFORE loading your code which depends on PHP vX.x+. Why? If you put a PHP vX.x+ check at the top of an existing PHP file, and that particular PHP file happens to contain code which is only valid in PHP v5.2 (for instance), it may still trigger a syntax error. For this reason, you should move your code into a separate file and create a stub file that checks for the existence of PHP vX.x+ first.
74
+
75
+ ---
76
+
77
+ ### Can I test for required PHP extensions too?
78
+
79
+ Yes, `$GLOBALS['wp_php_rv']` can be either a string with a required version, or an array with both a required version and a nested array of required PHP extensions. The easiest way to show how this works is by example (as seen below). Note that your array of required PHP extensions must be compatible with PHP's [`extension_loaded()`](http://php.net/manual/en/function.extension-loaded.php) function.
80
+
81
+ ```php
82
+ <?php
83
+ $GLOBALS['wp_php_rv']['min'] = '5.3';
84
+ $GLOBALS['wp_php_rv']['extensions'] = array('curl', 'mbstring');
85
+
86
+ if(require('wp-php-rv/src/includes/check.php')) // `true` if running PHP vX.x+ w/ all required extensions.
87
+ require dirname(__FILE__).'/my-plugin-code.php'; // It's OK to load your plugin.
88
+ else wp_php_rv_notice('My Plugin'); // Dashboard notice mentions your software specifically.
89
+ ```
90
+
91
+ ---
92
+
93
+ ### What else can I test for with this system?
94
+
95
+ A compatible OS, a compatible PHP version, required bits, required PHP functions, required PHP extensions, and a compatible WP version.
96
+
97
+ ```php
98
+ <?php
99
+ $GLOBALS['wp_php_rv']['os'] = 'nix'; // Requires a Unix-like OS.
100
+ // This is one of two operating system identifiers (always in lowercase): `nix` or `win`
101
+ // As far as WP PHP RV is concerned, their OS is either `nix` (Unix-like) or `win` (Windows).
102
+ // If you only want to support Unix-like systems, set this to: `nix`, making Windows incompatible.
103
+ // If you only want to support Windows systems, set this to: `win`, making others incompatible.
104
+
105
+ $GLOBALS['wp_php_rv']['min'] = '5.3'; // Minimum PHP version.
106
+ $GLOBALS['wp_php_rv']['max'] = '7.0.4'; // Max compatible PHP version, if applicable.
107
+
108
+ $GLOBALS['wp_php_rv']['bits'] = 64; // e.g., 32 or 64 bit architecture.
109
+ $GLOBALS['wp_php_rv']['functions'] = array('eval'); // Functions (or constructs).
110
+ $GLOBALS['wp_php_rv']['extensions'] = array('curl', 'mbstring'); // See previous FAQ.
111
+
112
+ $GLOBALS['wp_php_rv']['wp']['min'] = '4.2'; // Minimum WP version.
113
+ $GLOBALS['wp_php_rv']['wp']['max'] = '4.5.2'; // Max compatible WP version, if applicable.
114
+
115
+ if(require('wp-php-rv/src/includes/check.php')) // `true` if no issue.
116
+ require dirname(__FILE__).'/my-plugin-code.php'; // It's OK to load your plugin.
117
+ else wp_php_rv_notice('My Plugin'); // Dashboard notice mentions your software specifically.
118
+ ```
119
+
120
+ ---
121
+
122
+ Copyright: © 2015 [WebSharks, Inc.](http://www.websharks-inc.com/bizdev/) (coded in the USA)
123
+
124
+ Released under the terms of the [GNU General Public License](http://www.gnu.org/licenses/gpl-3.0.html).