'."\n";
29 | echo '
'.__('Base Cache Directory (Must be Writable; i.e., Permissions 755 or Higher)', SLUG_TD).' '."\n";
30 | echo '
'.sprintf(__('This is where %1$s will store the cached version of your site. If you\'re not sure how to deal with directory permissions, don\'t worry too much about this. If there is a problem, %1$s will let you know about it. By default, this directory is created by %1$s and the permissions are setup automatically. In most cases there is nothing more you need to do.', SLUG_TD), esc_html(NAME)).'
'."\n";
31 | echo '
'."\n";
32 | echo '
'."\n";
33 |
34 | echo ''."\n";
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/includes/traits/Plugin/WcpCdnUtils.php:
--------------------------------------------------------------------------------
1 | options['cdn_enable']) {
26 | return -(integer) $this->options['cdn_invalidation_counter'];
27 | }
28 | if ($maybe && !$this->options['cache_clear_cdn_enable']) {
29 | return -(integer) $this->options['cdn_invalidation_counter'];
30 | }
31 | $this->updateOptions(['cdn_invalidation_counter' => ++$this->options['cdn_invalidation_counter']]);
32 |
33 | return (integer) $this->options['cdn_invalidation_counter'];
34 | }
35 |
36 | /**
37 | * Clears the CDN cache.
38 | *
39 | * @since 151002 Implementing CDN cache clearing.
40 | *
41 | * @param bool $manually True if clearing is done manually.
42 | * @param bool $maybe Defaults to a true value.
43 | *
44 | * @throws \Exception If a clear failure occurs.
45 | *
46 | * @return int CDN invalidation counter after clearing.
47 | * Zero, or a negative integer if clearing did not take place.
48 | */
49 | public function clearCdnCache($manually = false, $maybe = true)
50 | {
51 | return $this->wipeCdnCache($manually, $maybe);
52 | }
53 | }
54 | /*[/pro]*/
55 |
--------------------------------------------------------------------------------
/.build.props:
--------------------------------------------------------------------------------
1 | project_title = Comet Cache Pro
2 |
3 | project_owner = websharks
4 | project_slug = comet-cache-pro
5 | project_issues_slug = comet-cache
6 |
7 | project_namespace = WebSharks\\CometCache\\Pro
8 | project_sub_namespace = CometCachePro
9 |
10 | project_text_domain = comet-cache
11 | project_slack_channel = comet-cache
12 |
13 | project_version = %y%m%d
14 |
15 | project_php_required_version = 5.4
16 | project_php_tested_up_to_version = ${php.version}
17 |
18 | project_wp_required_version = 4.2
19 | project_wp_tested_up_to_version = 4.9-alpha
20 |
21 | project_other_zip_tgz_fileset_exclusions = README.md, **/composer.lock, **/composer.json, **/src/vendor/bin/, **/src/vendor/browscap/browscap-php/bin/, **/src/vendor/symfony/console/Resources/bin/
22 |
23 | project_lite_title = Comet Cache
24 | project_lite_slug = comet-cache
25 |
26 | project_lite_namespace = WebSharks\\CometCache
27 | project_lite_sub_namespace = CometCache
28 |
29 | project_lite_text_domain = comet-cache
30 | project_lite_text_domain_regex_replacement_pattern = \$this\-\>text_domain|SLUG_TD
31 |
32 | project_lite_alter_namespace_in_other_files_pattern = src/includes/templates/advanced-cache.txt
33 | project_lite_other_zip_tgz_fileset_exclusions = README.md, **/cdn-filters.txt, **/options-pro.png, **/pro-updater.png, **/stats.png, **/stats-f*.png, **/comet-cache-pro.pot, **/composer.lock, **/composer.json
34 |
--------------------------------------------------------------------------------
/src/includes/traits/Plugin/BbPressUtils.php:
--------------------------------------------------------------------------------
1 | isBbPressActive()) {
30 | return [];
31 | }
32 | if (!is_null($types = &$this->cacheKey('bbPressPostTypes'))) {
33 | return $types; // Already did this.
34 | }
35 | $types = []; // Initialize.
36 | $types[] = bbp_get_forum_post_type();
37 | $types[] = bbp_get_topic_post_type();
38 | $types[] = bbp_get_reply_post_type();
39 |
40 | return $types;
41 | }
42 |
43 | /**
44 | * bbPress post statuses.
45 | *
46 | * @since 150821 Improving bbPress support.
47 | *
48 | * @return array All bbPress post statuses.
49 | */
50 | public function bbPressStatuses()
51 | {
52 | if (!$this->isBbPressActive()) {
53 | return [];
54 | }
55 | if (!is_null($statuses = &$this->cacheKey('bbPressStatuses'))) {
56 | return $statuses; // Already did this.
57 | }
58 | $statuses = []; // Initialize.
59 |
60 | foreach (get_post_stati([], 'objects') as $_key => $_status) {
61 | if (isset($_status->label_count['domain']) && $_status->label_count['domain'] === 'bbpress') {
62 | $statuses[] = $_status->name;
63 | }
64 | }
65 | unset($_key, $_status); // Housekeeping.
66 |
67 | return $statuses;
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/src/includes/traits/Shared/BlogUtils.php:
--------------------------------------------------------------------------------
1 | siteid`.
16 | */
17 | public function getBlogs()
18 | {
19 | if (!is_multisite()) {
20 | return []; // Not possible.
21 | }
22 | $sites = []; // Initialize.
23 |
24 | foreach (get_sites([
25 | 'number' => 100, 'count' => false,
26 | 'network_id' => $GLOBALS['wpdb']->siteid,
27 | ]) as $_site) {
28 | if (($_site = get_site($_site))) {
29 | $sites[] = $_site->to_array();
30 | } // For compatibiliey with old `wp_get_sites()`.
31 | } // unset($_site);
32 |
33 | return $sites;
34 | }
35 |
36 | /**
37 | * Get blog details.
38 | *
39 | * @since 150821 Improving multisite compat.
40 | *
41 | * @param int $blog_id For which blog ID?
42 | *
43 | * @return \stdClass|null Blog details if possible.
44 | *
45 | * @note The return value of this function is NOT cached in support of `switch_to_blog()`.
46 | */
47 | public function blogDetails($blog_id = 0)
48 | {
49 | if (!is_multisite() || $this->isAdvancedCache()) {
50 | return null; // Not possible.
51 | }
52 | if (($blog_id = (int) $blog_id) < 0) {
53 | $blog_id = (int) get_current_site()->blog_id;
54 | }
55 | if (!$blog_id) {
56 | $blog_id = (int) get_current_blog_id();
57 | }
58 | if (!$blog_id || $blog_id < 0) {
59 | return null; // Not possible.
60 | }
61 | $details = get_blog_details($blog_id);
62 |
63 | return is_object($details) ? $details : null;
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/src/includes/traits/Plugin/WcpSitemapUtils.php:
--------------------------------------------------------------------------------
1 | cacheKey('autoClearXmlSitemapsCache'))) {
25 | return $counter; // Already did this.
26 | }
27 | $done = true; // Flag as having been done.
28 |
29 | if (!$this->options['enable']) {
30 | return $counter; // Nothing to do.
31 | }
32 | if (!$this->options['cache_clear_xml_sitemaps_enable']) {
33 | return $counter; // Nothing to do.
34 | }
35 | if (!$this->options['cache_clear_xml_sitemap_patterns']) {
36 | return $counter; // Nothing to do.
37 | }
38 | if (!is_dir($cache_dir = $this->cacheDir())) {
39 | return $counter; // Nothing to do.
40 | }
41 | if (!($regex_frags = $this->buildHostCachePathRegexFragsFromWcUris($this->options['cache_clear_xml_sitemap_patterns'], ''))) {
42 | return $counter; // There are no patterns to look for.
43 | }
44 | $regex = $this->buildHostCachePathRegex('', '\/'.$regex_frags.'\.');
45 | $counter += $this->clearFilesFromHostCacheDir($regex);
46 |
47 | if ($counter && is_admin() && (!IS_PRO || $this->options['change_notifications_enable'])) {
48 | $this->enqueueNotice(sprintf(__('Found %1$s in the cache for XML sitemaps; auto-clearing.', SLUG_TD), esc_html($this->i18nFiles($counter))), ['combinable' => true]);
49 | }
50 | return $counter;
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/includes/traits/Plugin/WcpUrlUtils.php:
--------------------------------------------------------------------------------
1 | cacheKey('autoClearUrlsCache'))) {
27 | return $counter; // Already did this.
28 | }
29 | $done = true; // Flag as having been done.
30 |
31 | if (!$this->options['enable']) {
32 | return $counter; // Nothing to do.
33 | }
34 | if (!$this->options['cache_clear_urls']) {
35 | return $counter; // Nothing to do.
36 | }
37 | if (!is_dir($cache_dir = $this->cacheDir())) {
38 | return $counter; // Nothing to do.
39 | }
40 | foreach (preg_split('/['."\r\n".']+/', $this->options['cache_clear_urls'], -1, PREG_SPLIT_NO_EMPTY) as $_url) {
41 | if (mb_stripos($_url, 'http') === 0) {
42 | $_regex = $this->buildCachePathRegexFromWcUrl($_url);
43 | $counter += $this->deleteFilesFromCacheDir($_regex);
44 | }
45 | }
46 | unset($_url, $_regex); // Housekeeping.
47 |
48 | if ($counter && is_admin() && (!IS_PRO || $this->options['change_notifications_enable'])) {
49 | $this->enqueueNotice(sprintf(__('Found %1$s in the cache matching a custom list of URLs; auto-clearing.', SLUG_TD), esc_html($this->i18nFiles($counter))), ['combinable' => true]);
50 | }
51 | return $counter;
52 | }
53 | }
54 | /*[/pro]*/
55 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "type": "library",
3 | "license": "GPL-3.0+",
4 | "name": "websharks/comet-cache-pro",
5 |
6 | "homepage": "https://github.com/websharks/comet-cache-pro",
7 | "support": {
8 | "source": "https://github.com/websharks/comet-cache-pro",
9 | "issues": "https://github.com/websharks/comet-cache/issues"
10 | },
11 |
12 | "description": "A popular caching plugin for WordPress.",
13 | "keywords": [
14 | "websharks",
15 | "comet cache",
16 | "wordpress",
17 | "caching",
18 | "cache"
19 | ],
20 |
21 | "authors": [{
22 | "name": "websharks",
23 | "homepage": "http://websharks.org",
24 | "role": "company"
25 | }, {
26 | "name": "jaswrks",
27 | "homepage": "http://jaswrks.com",
28 | "role": "developer"
29 | }, {
30 | "name": "raamdev",
31 | "homepage": "https://raamdev.com",
32 | "role": "developer"
33 | }],
34 |
35 | "require": {
36 | "php": ">=5.4",
37 | "websharks/sharkicons": "160221",
38 | "websharks/wp-php-rv": "160824.6416",
39 | "websharks/html-compressor": "170420.24924",
40 | "thadafinser/user-agent-parser": "1.5.0",
41 | "browscap/browscap-php": "3.0.0",
42 | "ramsey/uuid": "3.*"
43 | },
44 | "require-lite": {
45 | "php": ">=5.4",
46 | "websharks/sharkicons": "160221",
47 | "websharks/wp-php-rv": "160824.6416"
48 | },
49 | "require-dev": {
50 | "package/bourbon": "4.2.3",
51 | "websharks/wp-i18n-tools": "dev-master"
52 | },
53 |
54 | "autoload": {
55 | "psr-4": {
56 | "WebSharks\\CometCache\\Pro\\Classes\\": "src/includes/classes/",
57 | "WebSharks\\CometCache\\Pro\\Traits\\": "src/includes/traits/",
58 | "WebSharks\\CometCache\\Pro\\Interfaces\\": "src/includes/interfaces/"
59 | }
60 | },
61 | "config": {
62 | "vendor-dir": "src/vendor",
63 | "preferred-install": "dist"
64 | },
65 | "minimum-stability": "dev",
66 | "prefer-stable": true,
67 |
68 | "repositories": [{
69 | "type": "package",
70 | "package": {
71 | "name": "package/bourbon",
72 | "version": "4.2.3",
73 | "dist": {
74 | "url": "https://github.com/thoughtbot/bourbon/releases/download/v4.2.3/bourbon-v4.2.3.zip",
75 | "type": "zip"
76 | }
77 | }
78 | }]
79 | }
80 |
--------------------------------------------------------------------------------
/src/client-s/css/menu-pages/_colors.scss:
--------------------------------------------------------------------------------
1 | $anchor-color: #033A63;
2 | $anchor-hover-active-color: #467629;
3 |
4 | $pre-code-color: #eee;
5 | $pre-code-bg-color: #222;
6 | $pre-code-box-shadow-color: #000;
7 | $code-bg-color: rgba(178, 178, 178, 0.25);
8 |
9 | $hr-bg-color-a: rgba(0, 0, 0, 0);
10 | $hr-bg-color-b: rgba(0, 0, 0, 0.75);
11 | $hr-bg-color-c: rgba(0, 0, 0, 0);
12 |
13 | $img-screenshot-border-color: #afafaf;
14 | $img-screenshot-box-shadow-color: rgba(0, 0, 0, 0.2);
15 | $img-screenshot-bg-color: #fff;
16 |
17 | $primary-switch-color: #000;
18 | $primary-switch-bg-color: #f1e982;
19 | $primary-switch-border-color: rgba(0, 0, 0, 0.07);
20 | $primary-switch-box-shadow-color-a: rgba(0, 0, 0, 0.25);
21 | $primary-switch-box-shadow-color-b: #fff;
22 |
23 | $input-color: #333;
24 | $input-bg-color: #e8e8e8;
25 | $input-border-color: #848484;
26 | $input-box-shadow-color: rgba(132, 132, 132, 0.5);
27 |
28 | $input-focus-color: #000;
29 | $input-focus-bg-color: #e2e2e2;
30 | $input-focus-box-shadow-color-a: #fff;
31 | $input-focus-box-shadow-color-b: rgba(132, 132, 132, 0.25);
32 |
33 | $input-placeholder-color: rgba(0, 0, 0, 0.2);
34 |
35 | $button-color: #fff;
36 | $button-bg-color: #033A63;
37 | $button-hover-bg-color: #467629;
38 | $button-submit-bg-color: #467629;
39 | $button-submit-hover-bg-color: #033A63;
40 | $button-border-color: rgba(0, 0, 0, 0.5);
41 | $button-box-shadow-color-a: rgba(0, 0, 0, 0.25);
42 | $button-box-shadow-color-b: rgba(0, 0, 0, 0.2);
43 | $button-box-shadow-color-c: rgba(255, 255, 255, 0.1);
44 |
45 | $info-bg-color: #cadfed;
46 | $info-border-color: #216095;
47 |
48 | $notice-bg-color: #fffde8;
49 | $notice-border-color: #e6db55;
50 |
51 | $warning-bg-color: #ffefd3;
52 | $warning-border-color: #e6db55;
53 |
54 | $error-bg-color: #ffc0cb;
55 | $error-border-color: #711e1e;
56 |
57 | $heading-panel-togglers-bg-color: #033A63;
58 |
59 | $panel-heading-color: #eee;
60 | $panel-heading-hover-color: #fff;
61 | $panel-heading-bg-color: #033A63;
62 | $panel-heading-bg-color-fade: #20669A;
63 | $panel-heading-box-shadow-color: rgba(0, 0, 0, 0.25);
64 |
65 | $panel-body-color: #222;
66 | $panel-body-p-color: #666;
67 | $panel-body-p-notice-color: #000;
68 | $panel-body-bg-color: #fff;
69 | $panel-body-border-color: #848484;
70 | $panel-body-box-shadow-color-a: rgba(0, 0, 0, 0.25);
71 | $panel-body-box-shadow-color-b: rgba(0, 0, 0, 0.25);
72 |
--------------------------------------------------------------------------------
/src/includes/traits/Shared/ReplaceUtils.php:
--------------------------------------------------------------------------------
1 | strReplaceOnce($needle, $replace, $haystack, true);
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/includes/classes/MenuPage/Options/Safeguards.php:
--------------------------------------------------------------------------------
1 | '."\n";
23 |
24 | echo ' '."\n";
27 |
28 | echo ' '."\n";
29 | echo '
'."\n";
30 | echo '
'.__('Uninstall on Plugin Deletion; or Safeguard Options?', SLUG_TD).' '."\n";
31 | echo '
'.sprintf(__('Tip: By default, if you delete %1$s using the plugins menu in WordPress, nothing is lost. However, if you want to completely uninstall %1$s you should set this to Yes and THEN deactivate & delete %1$s from the plugins menu in WordPress. This way %1$s will erase your options for the plugin, erase directories/files created by the plugin, remove the advanced-cache.php file, terminate CRON jobs, etc. It erases itself from existence completely.', SLUG_TD), esc_html(NAME)).'
'."\n";
32 | echo '
'."\n";
33 | echo ' plugin->options['uninstall_on_deletion'], '0', false).'>'.__('Safeguard my options and the cache (recommended).', SLUG_TD).' '."\n";
34 | echo ' plugin->options['uninstall_on_deletion'], '1', false).'>'.sprintf(__('Yes, uninstall (completely erase) %1$s on plugin deletion.', SLUG_TD), esc_html(NAME)).' '."\n";
35 | echo '
'."\n";
36 | echo '
'."\n";
37 |
38 | echo ''."\n";
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/client-s/images/inline-icon.svg:
--------------------------------------------------------------------------------
1 | '."\n";
29 | echo '
'."\n";
30 | echo '
'.__('Caching Enabled for RSS, RDF, Atom Feeds?', SLUG_TD).' '."\n";
31 | echo '
'.__('This should almost ALWAYS be set to No. UNLESS, you\'re sure that you want to cache your feeds. If you use a web feed management provider like Google® Feedburner and you set this option to Yes, you may experience delays in the detection of new posts. NOTE: If you do enable this, it is highly recommended that you also enable automatic Feed Clearing too. Please see the section above: "Automatic Cache Clearing". Find the sub-section titled: "Auto-Clear RSS/RDF/ATOM Feeds".', SLUG_TD).'
'."\n";
32 | echo '
'."\n";
33 | echo ' plugin->options['feeds_enable'], '0', false).'>'.__('No, do NOT cache (or serve a cache file) when displaying a feed.', SLUG_TD).' '."\n";
34 | echo ' plugin->options['feeds_enable'], '1', false).'>'.__('Yes, I would like to cache feed URLs.', SLUG_TD).' '."\n";
35 | echo '
'."\n";
36 | echo '
'.__('Note: This option affects all feeds served by WordPress, including the site feed, the site comment feed, post-specific comment feeds, author feeds, search feeds, and category and tag feeds. See also: WordPress Feeds .', SLUG_TD).'
'."\n";
37 | echo '
'."\n";
38 |
39 | echo ''."\n";
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/includes/classes/MenuPage/Options/ImportExport.php:
--------------------------------------------------------------------------------
1 | plugin->isProPreview()) {
23 | echo ''."\n";
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/includes/traits/Shared/ServerUtils.php:
--------------------------------------------------------------------------------
1 | staticKey(__FUNCTION__))) {
18 | return $is; // Already cached this.
19 | }
20 | if (!empty($_SERVER['SERVER_SOFTWARE']) && is_string($_SERVER['SERVER_SOFTWARE'])) {
21 | if (mb_stripos($_SERVER['SERVER_SOFTWARE'], 'apache') !== false) {
22 | return $is = true;
23 | } elseif (mb_stripos($_SERVER['SERVER_SOFTWARE'], 'litespeed') !== false) {
24 | return $is = true;
25 | }
26 | } // Checking `SERVER_SOFTWARE` is faster.
27 |
28 | if ($this->functionIsPossible('apache_get_version')) {
29 | return $is = true;
30 | }
31 | return $is = false;
32 | }
33 |
34 | /**
35 | * Is running on Nginx?
36 | *
37 | * @since 151002 This is Nginx?
38 | *
39 | * @return bool True if running Nginx.
40 | */
41 | public function isNginx()
42 | {
43 | if (!is_null($is = &$this->staticKey(__FUNCTION__))) {
44 | return $is; // Already cached this.
45 | }
46 | if (!empty($_SERVER['SERVER_SOFTWARE']) && is_string($_SERVER['SERVER_SOFTWARE'])) {
47 | if (mb_stripos($_SERVER['SERVER_SOFTWARE'], 'nginx') !== false) {
48 | return $is = true;
49 | }
50 | } // Checking `SERVER_SOFTWARE` is faster.
51 |
52 | if (!empty($_SERVER['WP_NGINX_CONFIG'])) {
53 | return $is = true; // See:
54 | }
55 | return $is = false;
56 | }
57 |
58 | /**
59 | * Is running on Windows IIS?
60 | *
61 | * @since 151002 This is Windows IIS?
62 | *
63 | * @return bool True if running Windows IIS.
64 | */
65 | public function isIis()
66 | {
67 | if (!is_null($is = &$this->staticKey(__FUNCTION__))) {
68 | return $is; // Already cached this.
69 | }
70 | if (!empty($_SERVER['SERVER_SOFTWARE']) && is_string($_SERVER['SERVER_SOFTWARE'])) {
71 | if (mb_stripos($_SERVER['SERVER_SOFTWARE'], 'microsoft-iis') !== false) {
72 | return $is = true;
73 | } elseif (mb_stripos($_SERVER['SERVER_SOFTWARE'], 'expressiondevserver') !== false) {
74 | return $is = true;
75 | }
76 | } // Checking `SERVER_SOFTWARE` is faster.
77 |
78 | return $is = false;
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/src/includes/classes/MenuPage/Options/HostExclusions.php:
--------------------------------------------------------------------------------
1 | plugin->canConsiderDomainMapping());
24 |
25 | if ($this->plugin->applyWpFilters(GLOBAL_NS.'_exclude_hosts_option_enable', $exclude_hosts_option_enable)) {
26 | echo ''."\n";
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/includes/classes/MenuPage/Options/Developers.php:
--------------------------------------------------------------------------------
1 | '."\n";
23 |
24 | echo ' '."\n";
27 |
28 | echo ' '."\n";
29 | echo '
'."\n";
30 | echo '
'.__('Developing a Theme or Plugin for WordPress?', SLUG_TD).' '."\n";
31 | echo '
'.sprintf(__('Tip: %1$s can be disabled temporarily. If you\'re a theme/plugin developer, you can set a flag within your PHP code to disable the cache engine at runtime. Perhaps on a specific page, or in a specific scenario. In your PHP script, set: $_SERVER[\'COMET_CACHE_ALLOWED\'] = FALSE; or define(\'COMET_CACHE_ALLOWED\', FALSE). %1$s is also compatible with: define(\'DONOTCACHEPAGE\', TRUE). It does\'t matter where or when you define one of these, because %1$s is the last thing to run before script execution ends.', SLUG_TD), esc_html(NAME)).'
'."\n";
32 | echo '
'."\n";
33 | echo '
'.sprintf(__('Writing "Advanced Cache" Plugins Specifically for %1$s', SLUG_TD), esc_html(NAME)).' '."\n";
34 | echo '
'.sprintf(__('Theme/plugin developers can take advantage of the %1$s plugin architecture by creating PHP files inside this special directory: /wp-content/ac-plugins/. There is an example plugin file @ GitHub (please review it carefully and ask questions). If you develop a plugin for %1$s, please share it with the community by publishing it in the plugins respository at WordPress.org.', SLUG_TD), esc_html(NAME)).'
'."\n";
35 | echo '
'.sprintf(__('Why does %1$s have it\'s own plugin architecture? WordPress loads the advanced-cache.php drop-in file (for caching purposes) very early-on; before any other plugins or a theme. For this reason, %1$s implements it\'s own watered-down version of functions like add_action(), do_action(), add_filter(), apply_filters().', SLUG_TD), esc_html(NAME)).'
'."\n";
36 | echo '
'."\n";
37 |
38 | echo ''."\n";
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/includes/traits/Plugin/WcpOpcacheUtils.php:
--------------------------------------------------------------------------------
1 | options['cache_clear_opcache_enable']) {
24 | return $counter; // Not enabled at this time.
25 | }
26 | if (!$this->functionIsPossible('opcache_reset')) {
27 | return $counter; // Not possible.
28 | }
29 | if (!($status = $this->sysOpcacheStatus())) {
30 | return $counter; // Not possible.
31 | }
32 | if (empty($status->opcache_enabled)) {
33 | return $counter; // Not necessary.
34 | }
35 | if (empty($status->opcache_statistics->num_cached_keys)) {
36 | return $counter; // Not possible.
37 | }
38 | if ($files) { // Specific files?
39 | foreach ($files as $_file) {
40 | $counter += (int) opcache_invalidate($_file, true);
41 | } // unset($_file); // Housekeeping.
42 | } elseif (opcache_reset()) { // True if a reset occurs.
43 | $counter += $status->opcache_statistics->num_cached_keys;
44 | }
45 | return $counter;
46 | }
47 |
48 | /**
49 | * Clear (i.e., reset) OPCache.
50 | *
51 | * @since 151002 Adding OPCache support.
52 | *
53 | * @param bool $manually True if clearing is done manually.
54 | * @param bool $maybe Defaults to a true value.
55 | *
56 | * @return int Total keys cleared.
57 | */
58 | public function clearOpcache($manually = false, $maybe = true)
59 | {
60 | if (!is_multisite() || is_main_site() || current_user_can($this->network_cap)) {
61 | return $this->wipeOpcache($manually, $maybe);
62 | }
63 | return 0; // Not applicable.
64 | }
65 |
66 | /**
67 | * Wipe the Opcache (by force).
68 | *
69 | * @since 160521 Improving OPCache support.
70 | *
71 | * @return int Total keys cleared.
72 | */
73 | public function wipeOpcacheByForce()
74 | {
75 | return $this->wipeOpcache(false, false);
76 | }
77 |
78 | /**
79 | * Clear AC class file from Opcache (by force).
80 | *
81 | * @since 151215 Adding OPCache support.
82 | *
83 | * @return int Total keys cleared.
84 | */
85 | public function clearAcDropinFromOpcacheByForce()
86 | {
87 | return $this->wipeOpcache(false, false, [WP_CONTENT_DIR.'/advanced-cache.php']);
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/src/includes/classes/MenuPage/Options/UserAgentExclusions.php:
--------------------------------------------------------------------------------
1 | '."\n";
23 |
24 | echo ' '."\n";
27 |
28 | echo ' '."\n";
29 | echo '
'.__('Don\'t Cache These Special User-Agent Exclusion Patterns?', SLUG_TD).' '."\n";
30 | echo '
'.__('Sometimes there are special cases when a particular user-agent (e.g., a specific browser or a specific type of device); should be shown a page on your site that is NOT from the cache (and that resulting page should never be cached). This is where you will enter those if you need to (one per line). Searches are performed against the HTTP_USER_AGENT (caSe insensitive). A wildcard * character can also be used when necessary; e.g., Android *; Chrome/* Mobile (where * = 0 or more characters that are NOT a slash /). Other special characters include: ** = 0 or more characters of any kind, including / slashes; ^ = beginning of the string; $ = end of the string. To learn more about this syntax, please see this KB article .', SLUG_TD).'
'."\n";
31 | echo '
'."\n";
32 | echo '
'.sprintf(__('Tip: if you wanted to exclude iPhones put this line into the field above: iPhone;*AppleWebKit. Or, you could also just put in a small fragment, like: iphone; and that would exclude any user-agent containing that word fragment. Note, this is just an example. With a default installation of %1$s, there is no compelling reason to exclude iOS devices (or any mobile device for that matter).', SLUG_TD), esc_html(NAME)).'
'."\n";
33 | echo '
'.__('Note: please remember that your entries here should be formatted as a line-delimited list; e.g., one exclusion pattern per line.', SLUG_TD).'
'."\n";
34 | echo '
'."\n";
35 |
36 | echo ''."\n";
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/includes/classes/MenuPage/Options/RefererExclusions.php:
--------------------------------------------------------------------------------
1 | '."\n";
23 |
24 | echo ' '."\n";
27 |
28 | echo ' '."\n";
29 | echo '
'.__('Don\'t Cache These Special HTTP Referrer Exclusion Patterns?', SLUG_TD).' '."\n";
30 | echo '
'.__('Sometimes there are special cases where a particular referring URL (or referring domain) that sends you traffic; or even a particular group of referring URLs or domains that send you traffic; should result in a page being loaded on your site that is NOT from the cache (and that resulting page should never be cached). This is where you will enter those if you need to (one per line). Searches are performed against the HTTP_REFERER (caSe insensitive). A wildcard * character can also be used when necessary; e.g., *.domain.com (where * = 0 or more characters that are NOT a slash /). Other special characters include: ** = 0 or more characters of any kind, including / slashes; ^ = beginning of the string; $ = end of the string. To learn more about this syntax, please see this KB article .', SLUG_TD).'
'."\n";
31 | echo '
'."\n";
32 | echo '
'.__('Tip: let\'s use this example URL: http://www.referring-domain.com/search/?q=search+terms. To exclude this referring URL, you could put this line into the field above: www.referring-domain.com. Or, you could also just put in a small fragment, like: /search/ or q=*; and that would exclude any referrer containing that word fragment.', SLUG_TD).'
'."\n";
33 | echo '
'.__('Note: please remember that your entries here should be formatted as a line-delimited list; e.g., one exclusion pattern per line.', SLUG_TD).'
'."\n";
34 | echo '
'."\n";
35 |
36 | echo ''."\n";
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/includes/stub.php:
--------------------------------------------------------------------------------
1 | cacheKey('autoClearCustomPostTypeArchiveCache', $post_id))) {
30 | return $counter; // Already did this.
31 | }
32 | $done = true; // Flag as having been done.
33 |
34 | if (!$this->options['enable']) {
35 | return $counter; // Nothing to do.
36 | }
37 | if (!$this->options['cache_clear_custom_post_type_enable']) {
38 | return $counter; // Nothing to do.
39 | }
40 | if (!is_dir($cache_dir = $this->cacheDir())) {
41 | return $counter; // Nothing to do.
42 | }
43 | if (!($post_type = get_post_type($post_id))) {
44 | return $counter; // Nothing to do.
45 | }
46 | if (!($all_custom_post_types = get_post_types(['_builtin' => false]))) {
47 | return $counter; // No custom post types.
48 | }
49 | if (!in_array($post_type, array_keys($all_custom_post_types), true)) {
50 | return $counter; // This is NOT a custom post type.
51 | }
52 | if (!($custom_post_type = get_post_type_object($post_type))) {
53 | return $counter; // Unable to retrieve post type.
54 | }
55 | if (empty($custom_post_type->labels->name) || !($custom_post_type_name = $custom_post_type->labels->name)) {
56 | $custom_post_type_name = __('Untitled', SLUG_TD);
57 | }
58 | if (!($custom_post_type_archive_link = get_post_type_archive_link($post_type))) {
59 | return $counter; // Nothing to do; no link to work from in this case.
60 | }
61 | $regex = $this->buildHostCachePathRegex($custom_post_type_archive_link);
62 | $counter += $this->clearFilesFromHostCacheDir($regex);
63 |
64 | if ($counter && is_admin() && (!IS_PRO || $this->options['change_notifications_enable'])) {
65 | $this->enqueueNotice(sprintf(__('Found %1$s in the cache for Custom Post Type: %2$s; auto-clearing.', SLUG_TD), esc_html($this->i18nFiles($counter)), esc_html($custom_post_type_name)), ['combinable' => true]);
66 | }
67 | $counter += $this->autoClearXmlFeedsCache('custom-post-type', $post_id);
68 |
69 | return $counter;
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/src/includes/classes/AdvancedCache.php:
--------------------------------------------------------------------------------
1 | is_running = true;
80 | $this->timer = microtime(true);
81 |
82 | $this->loadAcPlugins();
83 | $this->registerShutdownFlag();
84 | $this->maybeIgnoreUserAbort();
85 | $this->maybeStopBrowserCaching();
86 | /*[pro strip-from="lite"]*/
87 | $this->maybePostloadInvalidateWhenLoggedIn();
88 | /*[/pro]*/
89 | $this->maybeStartOutputBuffering();
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/src/includes/classes/MenuPage/Options/UriExclusions.php:
--------------------------------------------------------------------------------
1 | '."\n";
23 |
24 | echo ' '."\n";
27 |
28 | echo ' '."\n";
29 | echo '
'.__('Don\'t Cache These Special URI Exclusion Patterns?', SLUG_TD).' '."\n";
30 | echo '
'.__('Sometimes there are certain cases where a particular file, or a particular group of files, should never be cached. This is where you will enter those if you need to (one per line). Searches are performed against the REQUEST_URI ; i.e., /path/?query (caSe insensitive). So, don\'t put in full URLs here, just word fragments found in the file path (or query string) is all you need, excluding the http:// and domain name. A wildcard * character can also be used when necessary; e.g., /category/abc-followed-by-* (where * = 0 or more characters that are NOT a slash /). Other special characters include: ** = 0 or more characters of any kind, including / slashes; ^ = beginning of the string; $ = end of the string. To learn more about this syntax, please see this KB article .', SLUG_TD).'
'."\n";
31 | echo '
'."\n";
32 |
33 | echo '
'.__('Tip: let\'s use this example URL: http://www.example.com/post/example-post-123. To exclude this URL, you would put this line into the field above: /post/example-post-123. Or, you could also just put in a small fragment, like: example or example-*-123 and that would exclude any URI containing that word fragment.', SLUG_TD).'
'."\n";
34 | echo '
'.__('Note: please remember that your entries here should be formatted as a line-delimited list; e.g., one exclusion pattern per line.', SLUG_TD).'
'."\n";
35 | if (is_multisite() && defined('SUBDOMAIN_INSTALL') && !SUBDOMAIN_INSTALL) {
36 | echo '
'.__('Multisite Network w/ Sub-Directories: You can also use URI Exclusion Patterns to exclude specific sites from being cached, e.g., /site1/*.', SLUG_TD).'
'."\n";
37 | }
38 | echo '
'."\n";
39 |
40 | echo ''."\n";
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/includes/classes/Notes.php:
--------------------------------------------------------------------------------
1 | notes = [];
32 | }
33 |
34 | /**
35 | * Get notes.
36 | *
37 | * @since 161119 Notes.
38 | *
39 | * @return array Notes.
40 | */
41 | public function notes()
42 | {
43 | return $this->notes;
44 | }
45 |
46 | /**
47 | * Add note.
48 | *
49 | * @param string $key Key.
50 | * @param string $note Note.
51 | *
52 | * @since 161119 Notes.
53 | */
54 | public function add($key, $note)
55 | {
56 | $this->notes[$key] = $note;
57 | }
58 |
59 | /**
60 | * Add line break.
61 | *
62 | * @since 161119 Notes.
63 | */
64 | public function addLineBreak()
65 | {
66 | $this->notes[] = "\n";
67 | }
68 |
69 | /**
70 | * Add divider.
71 | *
72 | * @since 161119 Notes.
73 | */
74 | public function addDivider()
75 | {
76 | $this->notes[] = str_repeat('.', 70);
77 | }
78 |
79 | /**
80 | * Add ASCII artwork.
81 | *
82 | * @param string $note Note.
83 | *
84 | * @since 161119 Notes.
85 | */
86 | public function addAsciiArt($note)
87 | {
88 | $this->notes[] = '*´¨)
89 | ¸.•´¸.•*´¨) ¸.•*¨)
90 | (¸.•´ (¸.•` ¤ '.$note.' ¤ ´¨)';
91 | }
92 |
93 | /**
94 | * As HTML comments.
95 | *
96 | * @since 161119 HTML comments.
97 | */
98 | public function asHtmlComments()
99 | {
100 | $html_comments = ''; // Initialize.
101 | $longest_key_size = 0; // Initialize.
102 |
103 | foreach ($this->notes as $_key => $_note) {
104 | if (is_string($_key) && $_key && isset($_note[0])) {
105 | $longest_key_size = max($longest_key_size, mb_strlen($_key.':'));
106 | }
107 | } // unset($_key, $_note); // Housekeeping.
108 |
109 | foreach ($this->notes as $_key => $_note) {
110 | if (is_integer($_key)) {
111 | if ($_note === "\n") {
112 | $html_comments .= "\n";
113 | } elseif (isset($_note[0])) {
114 | $html_comments .= ''."\n";
115 | }
116 | } elseif ($_key && !isset($_note[0])) {
117 | $html_comments .= ''."\n";
118 | } elseif (!$_key && isset($_note[0])) {
119 | $html_comments .= ''."\n";
120 | } elseif ($_key && isset($_note[0])) {
121 | $html_comments .= ''."\n";
122 | }
123 | } // unset($_key, $_note); // Housekeeping.
124 |
125 | return trim($html_comments);
126 | }
127 | }
128 |
--------------------------------------------------------------------------------
/src/includes/classes/MenuPage/Options/Nf404Requests.php:
--------------------------------------------------------------------------------
1 | '."\n";
23 |
24 | echo ' '."\n";
27 |
28 | echo ' '."\n";
29 | echo '
'."\n";
30 | echo '
'.__('Caching Enabled for 404 Requests?', SLUG_TD).' '."\n";
31 | echo '
'.sprintf(__('When this is set to No, %1$s will ignore all 404 requests and no cache file will be served. While this is fine for most site owners, caching the 404 page on a high-traffic site may further reduce server load. When this is set to Yes, %1$s will cache the 404 page (see Creating an Error 404 Page ) and then serve that single cache file to all future 404 requests.', SLUG_TD), esc_html(NAME)).'
'."\n";
32 | echo '
'."\n";
33 | echo ' plugin->options['cache_404_requests'], '0', false).'>'.__('No, do NOT cache (or serve a cache file) for 404 requests.', SLUG_TD).' '."\n";
34 | echo ' plugin->options['cache_404_requests'], '1', false).'>'.__('Yes, I would like to cache the 404 page and serve the cached file for 404 requests.', SLUG_TD).' '."\n";
35 | echo '
'."\n";
36 | echo '
'.sprintf(__('How does %1$s cache 404 requests? %1$s will create a special cache file (----404----.html, see Advanced Tip below) for the first 404 request and then symlink future 404 requests to this special cache file. That way you don\'t end up with lots of 404 cache files that all contain the same thing (the contents of the 404 page). Instead, you\'ll have one 404 cache file and then several symlinks (i.e., references) to that 404 cache file.', SLUG_TD), esc_html(NAME)).'
'."\n";
37 | echo '
'.__('Advanced Tip: The default 404 cache filename (----404----.html) is designed to minimize the chance of a collision with a cache file for a real page with the same name. However, if you want to override this default and define your own 404 cache filename, you can do so by adding define(\'COMET_CACHE_404_CACHE_FILENAME\', \'your-404-cache-filename\'); to your wp-config.php file (note that the .html extension should be excluded when defining a new filename).', SLUG_TD).'
'."\n";
38 | echo '
'."\n";
39 |
40 | echo ''."\n";
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/includes/traits/Shared/SysUtils.php:
--------------------------------------------------------------------------------
1 | cacheKey('sysLoadAverages'))) {
18 | return $averages; // Already cached these.
19 | }
20 | if (!$this->functionIsPossible('sys_getloadavg')) {
21 | return $averages = [];
22 | }
23 | if (!is_array($averages = sys_getloadavg()) || !$averages) {
24 | return $averages = [];
25 | }
26 | $averages = array_map('floatval', $averages);
27 | $averages = array_slice($averages, 0, 3);
28 | // i.e., 1m, 5m, 15m; see:
29 |
30 | return $averages;
31 | }
32 |
33 | /**
34 | * System memory info.
35 | *
36 | * @since 151002 Adding cache directory statistics.
37 | *
38 | * @return \stdClass|bool System memory info.
39 | */
40 | public function sysMemoryStatus()
41 | {
42 | if (!is_null($status = &$this->cacheKey('sysMemoryStatus'))) {
43 | return $status; // Already cached this.
44 | }
45 | if (!$this->functionIsPossible('shell_exec')) {
46 | return $status = false;
47 | }
48 | if (!($free = trim((string) @shell_exec('free')))) {
49 | return $status = false;
50 | }
51 | if (!($free_lines = explode("\n", $free))) {
52 | return $status = false;
53 | }
54 | if (empty($free_lines[1])) {
55 | return $status = false;
56 | }
57 | if (!($memory = explode(' ', $free_lines[1]))) {
58 | return $status = false;
59 | }
60 | if (!($memory = array_merge(array_filter($memory)))) {
61 | return $status = false;
62 | }
63 | if (!isset($memory[1], $memory[2])) {
64 | return $status = false;
65 | }
66 | if (($total = (integer) $memory[1]) <= 0) {
67 | return $status = false;
68 | }
69 | $used = (integer) $memory[2];
70 | $percent = $used / $total * 100;
71 | $percentage = sprintf(__('%s%%', SLUG_TD), number_format($percent, 2, '.', ''));
72 | $status = (object) compact('total', 'used', 'percent', 'percentage');
73 |
74 | return $status;
75 | }
76 |
77 | /**
78 | * System opcache status/details.
79 | *
80 | * @since 151002 Adding cache directory statistics.
81 | *
82 | * @return \stdClass|bool System opcache status/details.
83 | */
84 | public function sysOpcacheStatus()
85 | {
86 | if (!is_null($status = &$this->cacheKey('sysOpcacheStatus'))) {
87 | return $status; // Already cached this.
88 | }
89 | if (!$this->functionIsPossible('opcache_get_status')) {
90 | return $status = false;
91 | }
92 | if (!is_array($status = opcache_get_status(false)) || !$status) {
93 | return $status = false;
94 | }
95 | if (empty($status['opcache_enabled'])) {
96 | return $status = false;
97 | }
98 | return json_decode(json_encode($status));
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/src/client-s/css/menu-pages/_heading.scss:
--------------------------------------------------------------------------------
1 | .plugin-menu-page-heading {
2 | .plugin-menu-page-stats-button {
3 | float: right;
4 |
5 | @media (max-width: 1199px) {
6 | float: none;
7 | display: block;
8 | margin: auto;
9 | }
10 | }
11 |
12 | .plugin-menu-page-restore-defaults {
13 | float: right;
14 | margin: 0 1em 0 0;
15 |
16 | @media (max-width: 1199px) {
17 | float: none;
18 | clear: left;
19 | text-align: center;
20 | margin: 0 auto;
21 | }
22 | }
23 |
24 | .plugin-menu-page-panel-togglers {
25 | float: right;
26 | margin: 0 1em 0 0;
27 |
28 | @media (max-width: 1199px) {
29 | display: none;
30 | }
31 |
32 | button {
33 | background: $heading-panel-togglers-bg-color !important;
34 | }
35 | }
36 |
37 | .plugin-menu-page-upsells {
38 | float: right;
39 | clear: right;
40 | text-align: right;
41 | max-width: 350px;
42 | margin: 1em 0 0;
43 |
44 | @media (max-width: 1199px) {
45 | float: none;
46 | clear: both;
47 | text-align: center;
48 | margin: 0 auto 0 auto;
49 | padding: 1em 0 0 0;
50 | }
51 |
52 | a {
53 | text-decoration: none;
54 | line-height: 1.5em;
55 | margin: 0 0.5em;
56 | display: inline-block;
57 | }
58 | }
59 |
60 | .plugin-menu-page-support-links {
61 | float: right;
62 | clear: right;
63 | text-align: right;
64 | max-width: 400px;
65 | margin: .5em 0 0;
66 |
67 | @media (max-width: 1199px) {
68 | float: none;
69 | clear: both;
70 | text-align: center;
71 | margin: 1em auto 1em auto;
72 | }
73 |
74 | a {
75 | text-decoration: none;
76 | margin: 0 0.5em;
77 | display: inline-block;
78 | }
79 | }
80 |
81 | .plugin-menu-page-mailing-list-links {
82 | float: right;
83 | clear: right;
84 | text-align: right;
85 | max-width: 400px;
86 | margin: .5em 0 0;
87 |
88 | @media (max-width: 1199px) {
89 | float: none;
90 | clear: both;
91 | text-align: center;
92 | margin: 1em auto 1em auto;
93 | }
94 |
95 | a {
96 | text-decoration: none;
97 | margin: 0 0.5em;
98 | display: inline-block;
99 | }
100 | }
101 |
102 | .plugin-menu-page-version {
103 | float: right;
104 | clear: right;
105 | min-width: 350px;
106 | margin: 0.5em 0 0 0;
107 | text-align: right;
108 |
109 | @media (max-width: 1199px) {
110 | float: none;
111 | clear: both;
112 | text-align: center;
113 | }
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/src/includes/traits/Shared/CacheLockUtils.php:
--------------------------------------------------------------------------------
1 | applyWpFilters(GLOBAL_NS.'\\share::disable_cache_locking', false)
25 | || $this->applyWpFilters(GLOBAL_NS.'_disable_cache_locking', false)
26 | ) {
27 | return false; // Disabled cache locking.
28 | }
29 | if (!($wp_config_file = $this->findWpConfigFile())) {
30 | throw new \Exception(__('Unable to find the wp-config.php file.', SLUG_TD));
31 | }
32 | $lock_type = 'flock'; // Default lock type.
33 | $lock_type = $this->applyWpFilters(GLOBAL_NS.'\\share::cache_lock_lock_type', $lock_type);
34 | $lock_type = $this->applyWpFilters(GLOBAL_NS.'_cache_lock_type', $lock_type);
35 |
36 | if (!in_array($lock_type, ['flock', 'sem'], true)) {
37 | $lock_type = 'flock'; // Default lock type.
38 | }
39 | if ($lock_type === 'sem' && $this->functionIsPossible('sem_get')) {
40 | if (($ipc_key = ftok($wp_config_file, 'w'))) {
41 | if (($resource = sem_get($ipc_key, 1)) && sem_acquire($resource)) {
42 | return ['type' => 'sem', 'resource' => $resource];
43 | }
44 | }
45 | }
46 | if (!($tmp_dir = $this->getTmpDir())) {
47 | throw new \Exception(__('No writable tmp directory.', SLUG_TD));
48 | }
49 | $inode_key = fileinode($wp_config_file);
50 | $mutex = $tmp_dir.'/'.SLUG_TD.'-'.$inode_key.'.lock';
51 |
52 | if (!($resource = fopen($mutex, 'wb')) || !flock($resource, LOCK_EX)) {
53 | throw new \Exception(__('Unable to obtain an exclusive lock.', SLUG_TD));
54 | }
55 |
56 | @chmod($mutex, 0666); // See https://git.io/v2WAt
57 |
58 | return ['type' => 'flock', 'resource' => $resource];
59 | }
60 |
61 | /**
62 | * Release an exclusive lock on the cache directory.
63 | *
64 | * @since 150422 Rewrite. Updated 151002 to remove the `array` typecast.
65 | *
66 | * @param array|mixed $lock Type & resource.
67 | */
68 | public function cacheUnlock($lock)
69 | {
70 | if (!is_array($lock)) {
71 | return; // Not possible.
72 | // Or, they disabled cache locking.
73 | }
74 | if (empty($lock['type']) || empty($lock['resource'])) {
75 | return; // Not possible.
76 | }
77 | if (!is_resource($lock['resource'])) {
78 | return; // Not possible.
79 | }
80 | if ($lock['type'] === 'sem') {
81 | sem_release($lock['resource']);
82 | } elseif ($lock['type'] === 'flock') {
83 | flock($lock['resource'], LOCK_UN);
84 | fclose($lock['resource']);
85 | }
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/src/includes/interfaces/Shared/CachePathConsts.php:
--------------------------------------------------------------------------------
1 | &$_GET,
22 | '_REQUEST' => &$_REQUEST,
23 | ];
24 | $key_suffixes = ['AC', 'ABC'];
25 | $lc_short_name = mb_strtolower(SHORT_NAME);
26 |
27 | foreach ($super_globals as $_key => &$_array) {
28 | foreach ($key_suffixes as $_suffix) {
29 | if (!array_key_exists('zc'.$_suffix, $_array)) {
30 | continue; // No relevant key in array.
31 | }
32 | if ($_key === '_GET' && !isset($_GET[$lc_short_name.$_suffix])) {
33 | $_GET[$lc_short_name.$_suffix] = $_array['zc'.$_suffix];
34 | } // This sets the new key with the value from the old key.
35 |
36 | foreach ($super_globals as $__key => &$__array) {
37 | unset($__array['zc'.$_suffix]); // Purge old key.
38 | } // Must unset temporary vars by reference.
39 | unset($__key, $__array); // Housekeeping.
40 | //
41 | } // unset($_suffix); // Housekeeping.
42 | } // Must unset temporary vars by reference.
43 | unset($_key, $_array);
44 | }
45 |
46 | /**
47 | * Back compat. with `ZENCACHE_` constants.
48 | *
49 | * @since 150422 Rewrite.
50 | * @since 17xxxx Polishing a little.
51 | * @since 17xxxx Making this more dynamic.
52 | */
53 | public static function zenCacheConstants()
54 | {
55 | $uc_global_ns = mb_strtoupper(GLOBAL_NS);
56 |
57 | if (!($constants = get_defined_constants(true)) || empty($constants['user'])) {
58 | return; // Nothing to do; i.e. no user-defined constants.
59 | }
60 | foreach ($constants['user'] as $_constant => $_value) {
61 | if (mb_stripos($_constant, 'ZENCACHE_') !== 0) {
62 | continue; // Nothing to do here.
63 | } elseif (!($_constant_sub_name = mb_substr($_constant, 9))) {
64 | continue; // Nothing to do here.
65 | }
66 | if (!defined($uc_global_ns.'_'.$_constant_sub_name)) {
67 | define($uc_global_ns.'_'.$_constant_sub_name, $_value);
68 | } // Sets new const with the value from the old const.
69 | } // unset($_constant, $_value); // Just a little housekeeping.
70 |
71 | if (isset($_SERVER['ZENCACHE_ALLOWED']) && !isset($_SERVER[$uc_global_ns.'_ALLOWED'])) {
72 | $_SERVER[$uc_global_ns.'_ALLOWED'] = $_SERVER['ZENCACHE_ALLOWED'];
73 | } // Sets new super-global with the value from the old super-global key.
74 | }
75 |
76 | /**
77 | * Back compat. with constants.
78 | *
79 | * @since 160706 Renaming `*_ALLOW_BROWSER_CACHE` to `*_ALLOW_CLIENT_SIDE_CACHE`.
80 | * @since 17xxxx Polishing things up a little.
81 | * @since 17xxxx Making this more dynamic.
82 | */
83 | public static function browserCacheConstant()
84 | {
85 | $uc_global_ns = mb_strtoupper(GLOBAL_NS);
86 |
87 | if (defined($uc_global_ns.'_ALLOW_BROWSER_CACHE')) {
88 | define($uc_global_ns.'_ALLOW_CLIENT_SIDE_CACHE', constant($uc_global_ns.'_ALLOW_BROWSER_CACHE'));
89 | }
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/src/includes/classes/MenuPageOptions.php:
--------------------------------------------------------------------------------
1 | GLOBAL_NS, '_wpnonce' => wp_create_nonce()]), self_admin_url('/admin.php'))).'">'."\n";
23 |
24 | new MenuPage\Options\Heading();
25 |
26 | /* ----------------------------------------------------------------------------------------- */
27 |
28 | echo ''."\n";
29 |
30 | /* ----------------------------------------------------------------------------------------- */
31 |
32 | echo '';
36 |
37 | new MenuPage\Options\Enable();
38 | new MenuPage\Options\ProUpdater();
39 | new MenuPage\Options\Safeguards();
40 |
41 | /* ----------------------------------------------------------------------------------------- */
42 |
43 | echo '';
47 |
48 | new MenuPage\Options\ManualClearing();
49 | new MenuPage\Options\AutomaticClearing();
50 |
51 | new MenuPage\Options\Statistics();
52 | new MenuPage\Options\Directory();
53 | new MenuPage\Options\Memcached();
54 | new MenuPage\Options\Expiration();
55 |
56 | new MenuPage\Options\ClientSide();
57 | new MenuPage\Options\UserRequests();
58 | new MenuPage\Options\GetRequests();
59 | new MenuPage\Options\Nf404Requests();
60 | new MenuPage\Options\FeedRequests();
61 |
62 | new MenuPage\Options\HostExclusions();
63 | new MenuPage\Options\UriExclusions();
64 | new MenuPage\Options\RefererExclusions();
65 | new MenuPage\Options\UserAgentExclusions();
66 |
67 | new MenuPage\Options\AutoCacheEngine();
68 | new MenuPage\Options\HtmlCompressor();
69 | new MenuPage\Options\StaticCdnFilters();
70 | new MenuPage\Options\ApacheOptimizations();
71 |
72 | new MenuPage\Options\MobileMode();
73 | new MenuPage\Options\VersionSalt();
74 |
75 | new MenuPage\Options\Developers();
76 | new MenuPage\Options\ImportExport();
77 |
78 | /* ----------------------------------------------------------------------------------------- */
79 |
80 | echo ''."\n";
83 |
84 | /* ----------------------------------------------------------------------------------------- */
85 |
86 | echo '
'."\n";
87 | echo '';
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/src/includes/traits/Plugin/DirUtils.php:
--------------------------------------------------------------------------------
1 | options['base_dir'])) {
26 | throw new \Exception(__('Missing `base_dir` option value.', SLUG_TD));
27 | }
28 | $wp_content_base_dir_to = WP_CONTENT_DIR.'/'.$this->options['base_dir'];
29 |
30 | if (isset($rel_dir_file[0])) {
31 | $wp_content_base_dir_to .= '/'.$rel_dir_file;
32 | }
33 | return $wp_content_base_dir_to;
34 | }
35 |
36 | /**
37 | * This constructs a relative/base directory path (no leading/trailing slashes).
38 | * Always relative to {@link \WP_CONTENT_DIR}. Depends on the configured `base_dir` option value.
39 | *
40 | * @since 150422 Rewrite.
41 | *
42 | * @param string $rel_dir_file A sub-directory or file; relative location please.
43 | *
44 | * @throws \Exception If `base_dir` is empty when this method is called upon;
45 | * i.e. if you attempt to call upon this method before {@link setup()} runs.
46 | *
47 | * @return string The relative/base directory path to `$rel_dir_file`.
48 | */
49 | public function basePathTo($rel_dir_file)
50 | {
51 | $rel_dir_file = trim((string) $rel_dir_file, '\\/'." \t\n\r\0\x0B");
52 |
53 | if (empty($this->options['base_dir'])) {
54 | throw new \Exception(__('Missing `base_dir` option value.', SLUG_TD));
55 | }
56 | $base_path_to = $this->options['base_dir'];
57 |
58 | if (isset($rel_dir_file[0])) {
59 | $base_path_to .= '/'.$rel_dir_file;
60 | }
61 | return $base_path_to;
62 | }
63 |
64 | /**
65 | * Get the absolute filesystem path to the root of the WordPress installation.
66 | *
67 | * Copied verbatim from get_home_path() in wp-admin/includes/file.php
68 | *
69 | * @since 151114 Adding `.htaccess` tweaks.
70 | *
71 | * @return string Full filesystem path to the root of the WordPress installation
72 | */
73 | public function wpHomePath()
74 | {
75 | $home = set_url_scheme(get_option('home'), 'http');
76 | $siteurl = set_url_scheme(get_option('siteurl'), 'http');
77 | if (!empty($home) && 0 !== strcasecmp($home, $siteurl) && !empty($_SERVER['SCRIPT_FILENAME'])) {
78 | $wp_path_rel_to_home = preg_replace('/'.preg_quote($home, '/').'/ui', '', $siteurl); /* $siteurl - $home */
79 | $pos = strripos(str_replace('\\', '/', $_SERVER['SCRIPT_FILENAME']), trailingslashit($wp_path_rel_to_home));
80 | $home_path = mb_substr($_SERVER['SCRIPT_FILENAME'], 0, $pos);
81 | $home_path = trailingslashit($home_path);
82 | } else {
83 | $home_path = ABSPATH;
84 | }
85 | return str_replace('\\', '/', $home_path);
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/src/includes/traits/Shared/IpAddrUtils.php:
--------------------------------------------------------------------------------
1 | staticKey('currentIp'))) {
21 | return $ip; // Already cached this.
22 | }
23 | $sources = [
24 | 'HTTP_CF_CONNECTING_IP',
25 | 'HTTP_CLIENT_IP',
26 | 'HTTP_X_FORWARDED_FOR',
27 | 'HTTP_X_FORWARDED',
28 | 'HTTP_X_CLUSTER_CLIENT_IP',
29 | 'HTTP_FORWARDED_FOR',
30 | 'HTTP_FORWARDED',
31 | 'HTTP_VIA',
32 | 'REMOTE_ADDR',
33 | ];
34 | $sources = $this->applyFilters(GLOBAL_NS.'\\share::current_ip_sources', $sources);
35 | $sources = $this->applyFilters(GLOBAL_NS.'_current_ip_sources', $sources);
36 |
37 | $prioritize_remote_addr = false; // Off by default; can be filtered however.
38 | $prioritize_remote_addr = $this->applyFilters(GLOBAL_NS.'\\share::current_ip_prioritize_remote_addr', $prioritize_remote_addr);
39 | $prioritize_remote_addr = $this->applyFilters(GLOBAL_NS.'_current_ip_prioritize_remote_addr', $prioritize_remote_addr);
40 |
41 | if (!empty($_SERVER['REMOTE_ADDR']) && $prioritize_remote_addr) {
42 | if (($_valid_public_ip = $this->validPublicIp((string) $_SERVER['REMOTE_ADDR']))) {
43 | return $ip = $_valid_public_ip;
44 | }
45 | unset($_valid_public_ip); // Housekeeping.
46 | }
47 | foreach ($sources as $_key => $_source) {
48 | if (!empty($_SERVER[$_source])) {
49 | if (($_valid_public_ip = $this->validPublicIp((string) $_SERVER[$_source]))) {
50 | return $ip = $_valid_public_ip;
51 | }
52 | }
53 | unset($_key, $_source, $_valid_public_ip); // Housekeeping.
54 | }
55 | if (!empty($_SERVER['REMOTE_ADDR'])) {
56 | return $ip = mb_strtolower((string) $_SERVER['REMOTE_ADDR']);
57 | }
58 | return $ip = 'unknown'; // Not possible.
59 | }
60 |
61 | /**
62 | * Gets a valid/public IP address.
63 | *
64 | * @since 150422 Rewrite.
65 | *
66 | * @param string $list_of_possible_ips A single IP, or a comma-delimited list of IPs.
67 | *
68 | * @return string A valid/public IP address (if one is found), else an empty string.
69 | *
70 | * @note This supports both IPv4 and IPv6 addresses.
71 | * @note See my tests against this here: http://3v4l.org/fVWUp
72 | */
73 | public function validPublicIp($list_of_possible_ips)
74 | {
75 | if (!$list_of_possible_ips || !is_string($list_of_possible_ips)) {
76 | return ''; // Empty or invalid data.
77 | }
78 | if (!($list_of_possible_ips = trim($list_of_possible_ips))) {
79 | return ''; // Not possible; i.e., empty string.
80 | }
81 | foreach (preg_split('/[\s;,]+/', $list_of_possible_ips, -1, PREG_SPLIT_NO_EMPTY) as $_key => $_possible_ip) {
82 | if (($_valid_public_ip = filter_var(mb_strtolower($_possible_ip), FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE))) {
83 | return $_valid_public_ip; // A valid public IPv4 or IPv6 address.
84 | }
85 | }
86 | unset($_key, $_possible_ip, $_valid_public_ip); // Housekeeping.
87 |
88 | return ''; // Default return value.
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/src/includes/traits/Shared/MemoryUtils.php:
--------------------------------------------------------------------------------
1 | isAdvancedCache()) {
32 | if (COMET_CACHE_MEMCACHED_ENABLE) {
33 | static::$memcached = new Classes\Memcached(COMET_CACHE_MEMCACHED_SERVERS);
34 | }
35 | } elseif ($this->isPlugin()) {
36 | if ($this->options['memcached_enable']) {
37 | static::$memcached = new Classes\Memcached($this->options['memcached_servers']);
38 | }
39 | }
40 | return static::$memcached = isset(static::$memcached) ? static::$memcached : false;
41 | }
42 |
43 | /**
44 | * Memory enabled?
45 | *
46 | * @since 17xxxx Memory utils.
47 | *
48 | * @return bool True if enabled.
49 | */
50 | public function memEnabled()
51 | {
52 | $instance = $this->memInstance();
53 | return $enabled = $instance instanceof Classes\Memcached && $instance->enabled();
54 | }
55 |
56 | /**
57 | * Get cache value by key.
58 | *
59 | * @since 17xxxx Memory utils.
60 | *
61 | * @param string $primary_key Primary key.
62 | * @param string|int $sub_key Sub-key to get.
63 | *
64 | * @return mixed|null Null if missing, or on failure.
65 | */
66 | public function memGet($primary_key, $sub_key)
67 | {
68 | $instance = $this->memInstance();
69 |
70 | if ($instance instanceof Classes\Memcached && $instance->enabled()) {
71 | return $instance->get($primary_key, $sub_key);
72 | }
73 | return null; // Not possible.
74 | }
75 |
76 | /**
77 | * Set|update cache key.
78 | *
79 | * @since 17xxxx Memory utils.
80 | *
81 | * @param string $primary_key Primary key.
82 | * @param string|int $sub_key Sub-key to set.
83 | * @param string $value Value to cache (1MB max).
84 | * @param int $expires_in Expires (in seconds).
85 | *
86 | * @return bool True on success.
87 | */
88 | public function memSet($primary_key, $sub_key, $value, $expires_in = 0)
89 | {
90 | $instance = $this->memInstance();
91 |
92 | if ($instance instanceof Classes\Memcached && $instance->enabled()) {
93 | return $instance->set($primary_key, $sub_key, $value, $expires_in);
94 | }
95 | return false; // Not possible.
96 | }
97 |
98 | /**
99 | * Clear the cache.
100 | *
101 | * @since 17xxxx Memory utils.
102 | *
103 | * @param string $primary_key Primary key.
104 | * @param string|int|null $sub_key Sub-key (optional).
105 | * @param int $delay Delay (in seconds).
106 | *
107 | * @return bool True on success.
108 | */
109 | public function memClear($primary_key, $sub_key = null, $delay = 0)
110 | {
111 | $instance = $this->memInstance();
112 |
113 | if ($instance instanceof Classes\Memcached && $instance->enabled()) {
114 | return $instance->clear($primary_key, $sub_key, $delay);
115 | }
116 | return false; // Not possible.
117 | }
118 | }
119 | /*[/pro]*/
120 |
--------------------------------------------------------------------------------
/src/includes/traits/Plugin/OptionUtils.php:
--------------------------------------------------------------------------------
1 | options = $this->default_options;
19 | return $this->getOptions();
20 | }
21 |
22 | /**
23 | * Get plugin options.
24 | *
25 | * @since 151002 Improving multisite compat.
26 | *
27 | * @param bool $intersect Discard options not present in $this->default_options
28 | * @param bool $refresh Force-pull options directly from get_site_option()
29 | *
30 | * @return array Plugin options.
31 | *
32 | * @note The `$intersect` param should be `false` when this method is called by a VS upgrade routine.
33 | * Also `false` during inital startup or when upgrading. See:
34 | */
35 | public function getOptions($intersect = true, $refresh = false)
36 | {
37 | if (!($options = $this->options) || $refresh) {
38 | if (!is_array($options = get_site_option(GLOBAL_NS.'_options'))) {
39 | $options = []; // Force an array of options.
40 | }
41 | if (!$options && is_array($zencache_options = get_site_option('zencache_options'))) {
42 | $options = $zencache_options;
43 | $options['crons_setup'] = $this->default_options['crons_setup'];
44 | $options['latest_pro_version'] = $this->default_options['latest_pro_version'];
45 | }
46 | } // End the collection of all plugin options.
47 |
48 | $this->options = array_merge($this->default_options, $options);
49 | $this->options = $this->applyWpFilters(GLOBAL_NS.'_options', $this->options);
50 | $this->options = $intersect ? array_intersect_key($this->options, $this->default_options) : $this->options;
51 | $this->options = array_map('trim', array_map('strval', $this->options));
52 |
53 | $this->options['base_dir'] = trim($this->options['base_dir'], '\\/'." \t\n\r\0\x0B");
54 | if (!$this->options['base_dir'] || mb_strpos(basename($this->options['base_dir']), 'wp-') === 0) {
55 | $this->options['base_dir'] = $this->default_options['base_dir'];
56 | }
57 | return $this->options; // Plugin options.
58 | }
59 |
60 | /**
61 | * Update plugin options.
62 | *
63 | * @since 151002 Improving multisite compat.
64 | *
65 | * @param array $options One or more new options.
66 | * @param bool $intersect Discard options not present in $this->default_options
67 | *
68 | * @return array Plugin options after update.
69 | *
70 | * @note $intersect should be `false` when this method is called via a VS upgrade routine. See https://git.io/viGIK
71 | */
72 | public function updateOptions(array $options, $intersect = true)
73 | {
74 | if (!IS_PRO) { // Do not save Pro option keys.
75 | $options = array_diff_key($options, $this->pro_only_option_keys);
76 | }
77 | if (!empty($options['base_dir']) && $options['base_dir'] !== $this->options['base_dir']) {
78 | $this->tryErasingAllFilesDirsIn($this->wpContentBaseDirTo(''));
79 | }
80 | if (IS_PRO && !empty($options['pro_update_username']) && !empty($options['pro_update_password'])) {
81 | $this->dismissMainNotice('configure-pro-updater');
82 | }
83 | $this->options = array_merge($this->default_options, $this->options, $options);
84 | $this->options = $intersect ? array_intersect_key($this->options, $this->default_options) : $this->options;
85 | $this->options = array_map('trim', array_map('strval', $this->options));
86 |
87 | update_site_option(GLOBAL_NS.'_options', $this->options);
88 |
89 | return $this->getOptions($intersect);
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/src/includes/traits/Ac/HtmlCUtils.php:
--------------------------------------------------------------------------------
1 | content_url) {
24 | return $cache; // Not possible.
25 | }
26 | if (!COMET_CACHE_HTMLC_ENABLE) {
27 | return $cache; // Nothing to do here.
28 | }
29 | if ($this->is_user_logged_in && !COMET_CACHE_HTMLC_WHEN_LOGGED_IN) {
30 | return $cache; // Nothing to do here.
31 | }
32 | // Deals with multisite base & sub-directory installs.
33 | // e.g. `htmlc/cache/public/www-example-com` (standard WP installation).
34 | // e.g. `htmlc/cache/public/[[/base]/child1]/www-example-com` (multisite network).
35 | // Note that `www-example-com` (current host slug) is appended by the HTML compressor.
36 |
37 | $host_base_dir_tokens = $this->hostBaseDirTokens(true); // Dashify this.
38 |
39 | $cache_dir_public = COMET_CACHE_HTMLC_CACHE_DIR_PUBLIC.rtrim($host_base_dir_tokens, '/');
40 | $cache_dir_url_public = $this->content_url.str_replace(WP_CONTENT_DIR, '', $cache_dir_public);
41 |
42 | $cache_dir_private = COMET_CACHE_HTMLC_CACHE_DIR_PRIVATE.rtrim($host_base_dir_tokens, '/');
43 | $cache_dir_url_private = $this->content_url.str_replace(WP_CONTENT_DIR, '', $cache_dir_private);
44 |
45 | $benchmark = COMET_CACHE_DEBUGGING_ENABLE >= 2 ? 'details' : COMET_CACHE_DEBUGGING_ENABLE;
46 | $product_title = sprintf(__('%1$s HTML Compressor', SLUG_TD), NAME);
47 |
48 | $html_compressor_options = [
49 | 'benchmark' => $benchmark,
50 | 'product_title' => $product_title,
51 |
52 | 'cache_dir_public' => $cache_dir_public,
53 | 'cache_dir_url_public' => $cache_dir_url_public,
54 |
55 | 'cache_dir_private' => $cache_dir_private,
56 | 'cache_dir_url_private' => $cache_dir_url_private,
57 |
58 | 'regex_css_exclusions' => COMET_CACHE_HTMLC_CSS_EXCLUSIONS,
59 | 'regex_js_exclusions' => COMET_CACHE_HTMLC_JS_EXCLUSIONS,
60 | 'regex_uri_exclusions' => COMET_CACHE_HTMLC_URI_EXCLUSIONS,
61 |
62 | 'cache_expiration_time' => COMET_CACHE_HTMLC_CACHE_EXPIRATION_TIME,
63 |
64 | 'compress_combine_head_body_css' => COMET_CACHE_HTMLC_COMPRESS_COMBINE_HEAD_BODY_CSS,
65 | 'compress_combine_head_js' => COMET_CACHE_HTMLC_COMPRESS_COMBINE_HEAD_JS,
66 | 'compress_combine_footer_js' => COMET_CACHE_HTMLC_COMPRESS_COMBINE_FOOTER_JS,
67 | 'compress_combine_remote_css_js' => COMET_CACHE_HTMLC_COMPRESS_COMBINE_REMOTE_CSS_JS,
68 | 'compress_inline_js_code' => COMET_CACHE_HTMLC_COMPRESS_INLINE_JS_CODE,
69 | 'compress_css_code' => COMET_CACHE_HTMLC_COMPRESS_CSS_CODE,
70 | 'compress_js_code' => COMET_CACHE_HTMLC_COMPRESS_JS_CODE,
71 | 'compress_html_code' => COMET_CACHE_HTMLC_COMPRESS_HTML_CODE,
72 | 'amp_exclusions_enable' => COMET_CACHE_HTMLC_AMP_EXCLUSIONS_ENABLE,
73 | ];
74 | try {
75 | $html_compressor = new \WebSharks\HtmlCompressor\Core($html_compressor_options);
76 | $compressed_cache = $html_compressor->compress($cache);
77 | } catch (\Exception $exception) {
78 | $compressed_cache = $cache; // Fail softly.
79 | if (COMET_CACHE_DEBUGGING_ENABLE >= 2) { // Leave a note in the source code?
80 | $compressed_cache .= "\n".'';
81 | }
82 | }
83 | return $compressed_cache.(COMET_CACHE_DEBUGGING_ENABLE ? "\n" : '');
84 | }
85 | }
86 | /*[/pro]*/
87 |
--------------------------------------------------------------------------------
/src/includes/traits/Plugin/WcpCommentUtils.php:
--------------------------------------------------------------------------------
1 | cacheKey('autoClearCommentPostCache', $comment_id))) {
29 | return $counter; // Already did this.
30 | }
31 | $done = true; // Flag as having been done.
32 |
33 | if (!$this->options['enable']) {
34 | return $counter; // Nothing to do.
35 | }
36 | if (!is_object($comment = get_comment($comment_id))) {
37 | return $counter; // Nothing we can do.
38 | }
39 | if (empty($comment->comment_post_ID)) {
40 | return $counter; // Nothing we can do.
41 | }
42 | if ($comment->comment_approved === 'spam' || $comment->comment_approved === '0') {
43 | // Don't allow next `autoClearPostCache()` call to clear post cache.
44 | $allow = &$this->cacheKey('autoClearPostCache_allow');
45 | $allow = false; // Flag as false; i.e., disallow.
46 | return $counter;
47 | }
48 | $counter += $this->autoClearXmlFeedsCache('blog-comments');
49 | $counter += $this->autoClearXmlFeedsCache('post-comments', $comment->comment_post_ID);
50 | $counter += $this->autoClearPostCache($comment->comment_post_ID);
51 |
52 | return $counter;
53 | }
54 |
55 | /**
56 | * Automatically clears cache files for a post associated with a particular comment.
57 | *
58 | * @since 150422 Rewrite.
59 | *
60 | * @attaches-to `transition_comment_status` hook.
61 | *
62 | * @param string $new_status New comment status.
63 | * @param string $old_status Old comment status.
64 | * @param \stdClass $comment Comment object.
65 | *
66 | * @throws \Exception If a clear failure occurs.
67 | *
68 | * @return int Total files cleared by this routine (if any).
69 | *
70 | * @note This is also called upon by other routines which listen for
71 | * events that are indirectly associated with a comment ID.
72 | */
73 | public function autoClearCommentPostCacheTransition($new_status, $old_status, $comment)
74 | {
75 | $counter = 0; // Initialize.
76 |
77 | if (!is_object($comment)) {
78 | return $counter; // Nothing we can do.
79 | }
80 | if (empty($comment->comment_post_ID)) {
81 | return $counter; // Nothing we can do.
82 | }
83 | if (!is_null($done = &$this->cacheKey('autoClearCommentPostCacheTransition', [$new_status, $old_status, $comment->comment_post_ID]))) {
84 | return $counter; // Already did this.
85 | }
86 | $done = true; // Flag as having been done.
87 |
88 | if (!$this->options['enable']) {
89 | return $counter; // Nothing to do.
90 | }
91 | if (!($old_status === 'approved' || ($old_status === 'unapproved' && $new_status === 'approved'))) {
92 | // If excluded here, don't allow next `autoClearPostCache()` call to clear post cache.
93 | $allow = &$this->cacheKey('autoClearPostCache_allow');
94 | $allow = false; // Flag as false; i.e., disallow.
95 | return $counter;
96 | }
97 | $counter += $this->autoClearXmlFeedsCache('blog-comments');
98 | $counter += $this->autoClearXmlFeedsCache('post-comments', $comment->comment_post_ID);
99 | $counter += $this->autoClearPostCache($comment->comment_post_ID);
100 |
101 | return $counter;
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/src/includes/traits/Plugin/WcpHomeBlogUtils.php:
--------------------------------------------------------------------------------
1 | cacheKey('autoClearHomePageCache'))) {
25 | return $counter; // Already did this.
26 | }
27 | $done = true; // Flag as having been done.
28 |
29 | if (!$this->options['enable']) {
30 | return $counter; // Nothing to do.
31 | }
32 | if (!$this->options['cache_clear_home_page_enable']) {
33 | return $counter; // Nothing to do.
34 | }
35 | if (!is_dir($cache_dir = $this->cacheDir())) {
36 | return $counter; // Nothing to do.
37 | }
38 | $regex = $this->buildHostCachePathRegex(home_url('/'));
39 | $counter += $this->clearFilesFromHostCacheDir($regex);
40 |
41 | if ($counter && is_admin() && (!IS_PRO || $this->options['change_notifications_enable'])) {
42 | $this->enqueueNotice(sprintf(__('Found %1$s in the cache for the designated "Home Page"; auto-clearing.', SLUG_TD), esc_html($this->i18nFiles($counter))), ['combinable' => true]);
43 | }
44 | $counter += $this->autoClearXmlFeedsCache('blog');
45 |
46 | return $counter;
47 | }
48 |
49 | /**
50 | * Automatically clears cache files for the posts page.
51 | *
52 | * @since 150422 Rewrite.
53 | *
54 | * @throws \Exception If a clear failure occurs.
55 | *
56 | * @return int Total files cleared by this routine (if any).
57 | *
58 | * @note Unlike many of the other `auto_` methods, this one is NOT currently
59 | * attached to any hooks. However, it is called upon by {@link autoClearPostCache()}.
60 | */
61 | public function autoClearPostsPageCache()
62 | {
63 | $counter = 0; // Initialize.
64 |
65 | if (!is_null($done = &$this->cacheKey('autoClearPostsPageCache'))) {
66 | return $counter; // Already did this.
67 | }
68 | $done = true; // Flag as having been done.
69 |
70 | if (!$this->options['enable']) {
71 | return $counter; // Nothing to do.
72 | }
73 | if (!$this->options['cache_clear_posts_page_enable']) {
74 | return $counter; // Nothing to do.
75 | }
76 | if (!is_dir($cache_dir = $this->cacheDir())) {
77 | return $counter; // Nothing to do.
78 | }
79 | $show_on_front = get_option('show_on_front');
80 | $page_for_posts = get_option('page_for_posts');
81 |
82 | if (!in_array($show_on_front, ['posts', 'page'], true)) {
83 | return $counter; // Nothing we can do in this case.
84 | }
85 | if ($show_on_front === 'page' && !$page_for_posts) {
86 | return $counter; // Nothing we can do.
87 | }
88 | if ($show_on_front === 'posts') {
89 | $posts_page = home_url('/');
90 | } elseif ($show_on_front === 'page') {
91 | $posts_page = get_permalink($page_for_posts);
92 | }
93 | if (empty($posts_page)) {
94 | return $counter; // Nothing we can do.
95 | }
96 | $regex = $this->buildHostCachePathRegex($posts_page);
97 | $counter += $this->clearFilesFromHostCacheDir($regex);
98 |
99 | if ($counter && is_admin() && (!IS_PRO || $this->options['change_notifications_enable'])) {
100 | $this->enqueueNotice(sprintf(__('Found %1$s in the cache for the designated "Posts Page"; auto-clearing.', SLUG_TD), esc_html($this->i18nFiles($counter))), ['combinable' => true]);
101 | }
102 | $counter += $this->autoClearXmlFeedsCache('blog');
103 |
104 | return $counter;
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/src/includes/traits/Plugin/CronUtils.php:
--------------------------------------------------------------------------------
1 | 900,
23 | 'display' => __('Every 15 Minutes', SLUG_TD),
24 | ];
25 | return $schedules;
26 | }
27 |
28 | /**
29 | * Checks cron setup, validates schedules, and reschedules events if necessary.
30 | *
31 | * @attaches-to `init` hook.
32 | *
33 | * @since 151220 Improving WP Cron setup and validation of schedules
34 | */
35 | public function checkCronSetup()
36 | {
37 | if ((!get_transient('doing_cron') && $this->options['crons_setup'] < 1439005906)
38 | || $this->options['crons_setup_on_namespace'] !== __NAMESPACE__
39 | || $this->options['crons_setup_with_cache_cleanup_schedule'] !== $this->options['cache_cleanup_schedule']
40 | || $this->options['crons_setup_on_wp_with_schedules'] !== sha1(serialize(wp_get_schedules()))
41 | || !wp_next_scheduled('_cron_'.GLOBAL_NS.'_cleanup')
42 | /*[pro strip-from="lite"]*/ // Auto-cache engine.
43 | || !wp_next_scheduled('_cron_'.GLOBAL_NS.'_auto_cache')
44 | /*[/pro]*/
45 | ) {
46 | wp_clear_scheduled_hook('_cron_'.GLOBAL_NS.'_cleanup');
47 | wp_schedule_event(time() + 60, $this->options['cache_cleanup_schedule'], '_cron_'.GLOBAL_NS.'_cleanup');
48 |
49 | /*[pro strip-from="lite"]*/ // Auto-cache engine.
50 | wp_clear_scheduled_hook('_cron_'.GLOBAL_NS.'_auto_cache');
51 | wp_schedule_event(time() + 60, 'every15m', '_cron_'.GLOBAL_NS.'_auto_cache');
52 | /*[/pro]*/
53 |
54 | $this->updateOptions(
55 | [
56 | 'crons_setup' => time(),
57 | 'crons_setup_on_namespace' => __NAMESPACE__,
58 | 'crons_setup_with_cache_cleanup_schedule' => $this->options['cache_cleanup_schedule'],
59 | 'crons_setup_on_wp_with_schedules' => sha1(serialize(wp_get_schedules())),
60 | ]
61 | );
62 | }
63 | }
64 |
65 | /**
66 | * Resets `crons_setup` and clears WP-Cron schedules.
67 | *
68 | * @since 151220 Fixing bug with Auto-Cache Engine cron disappearing in some scenarios
69 | *
70 | * @note This MUST happen upon uninstall and deactivation due to buggy WP_Cron behavior.
71 | * Events with a custom schedule will disappear when plugin is not active (see http://bit.ly/1lGdr78).
72 | */
73 | public function resetCronSetup()
74 | {
75 | if (is_multisite()) { // Main site CRON jobs.
76 | switch_to_blog(get_current_site()->blog_id);
77 | /*[pro strip-from="lite"]*/ // Auto-cache engine.
78 | wp_clear_scheduled_hook('_cron_'.GLOBAL_NS.'_auto_cache');
79 | /*[/pro]*/
80 | wp_clear_scheduled_hook('_cron_'.GLOBAL_NS.'_cleanup');
81 | restore_current_blog(); // Restore current blog.
82 | } else { // Standard WP installation.
83 | /*[pro strip-from="lite"]*/ // Auto-cache engine.
84 | wp_clear_scheduled_hook('_cron_'.GLOBAL_NS.'_auto_cache');
85 | /*[/pro]*/
86 | wp_clear_scheduled_hook('_cron_'.GLOBAL_NS.'_cleanup');
87 | }
88 | $this->updateOptions(
89 | [ // Reset so that crons are rescheduled upon next activation
90 | 'crons_setup' => $this->default_options['crons_setup'],
91 | 'crons_setup_on_namespace' => $this->default_options['crons_setup_on_namespace'],
92 | 'crons_setup_with_cache_cleanup_schedule' => $this->default_options['crons_setup_with_cache_cleanup_schedule'],
93 | 'crons_setup_on_wp_with_schedules' => $this->default_options['crons_setup_on_wp_with_schedules'],
94 | ]
95 | );
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/src/client-s/css/menu-pages/_panels.scss:
--------------------------------------------------------------------------------
1 | .plugin-menu-page-panel {
2 | margin: 1em 0;
3 |
4 | &:first-child {
5 | margin-top: 0;
6 | }
7 |
8 | .plugin-menu-page-panel-heading {
9 | @include user-select(none);
10 | @include sharkicon(chevron-down, after);
11 |
12 | text-decoration: none;
13 | padding: 10px;
14 | font-size: 150%;
15 | line-height: 1.125em;
16 | font-weight: 600;
17 | border-radius: 4px;
18 | display: block;
19 | cursor: pointer;
20 | background: $panel-heading-bg-color;
21 | background: linear-gradient(to right, $panel-heading-bg-color, $panel-heading-bg-color-fade);
22 | color: $panel-heading-color !important;
23 | box-shadow: 0 2px 2px 0 $panel-heading-box-shadow-color;
24 |
25 | &:hover,
26 | &.open {
27 | color: $panel-heading-hover-color !important;
28 | }
29 |
30 | &::after {
31 | font-size: 80%;
32 | float: right;
33 | margin: 0 0 0 5px;
34 | }
35 |
36 | &.open::after {
37 | content: map-get($sharkicons, chevron-up);
38 | }
39 |
40 | @at-root [data-pro-version-only*=' '] {
41 | @at-root .plugin-menu-page-panel-heading[data-pro-version-only*=' '] {
42 | background: #216095;
43 | }
44 |
45 | &::after {
46 | font-variant: small-caps !important;
47 | font-family: sans-serif !important;
48 | content: attr(data-pro-version-only) !important;
49 | margin-left: 15px;
50 | background: #216095;
51 | color: #FFFFFF;
52 | padding: 0 5px 2px 5px;
53 | font-weight: normal;
54 | }
55 | }
56 |
57 | @at-root [data-additional-pro-features*=' '] {
58 | @at-root .plugin-menu-page-panel-heading[data-additional-pro-features*=' '] {
59 | background: #216095;
60 | }
61 |
62 | &::after {
63 | font-variant: small-caps !important;
64 | font-family: sans-serif !important;
65 | content: attr(data-additional-pro-features) !important;
66 | margin-left: 15px;
67 | background: #216095;
68 | color: #FFFFFF;
69 | padding: 0 5px 2px 5px;
70 | font-weight: normal;
71 | }
72 | }
73 |
74 | > .si {
75 | text-align: center;
76 | width: 1.28571429em;
77 | margin-right: .25em;
78 | }
79 | }
80 |
81 | .plugin-menu-page-panel-body {
82 | width: 99%;
83 | margin: 0 auto;
84 | display: none;
85 | padding: 1.2em;
86 | border-bottom-left-radius: 4px;
87 | border-bottom-right-radius: 4px;
88 | box-sizing: border-box;
89 | color: $panel-body-color;
90 | border: 1px solid $panel-body-border-color;
91 | background: $panel-body-bg-color;
92 | box-shadow: 0 1px 1px 0 $panel-body-box-shadow-color-a, 0 3px 1px -1px $panel-body-box-shadow-color-b inset;
93 |
94 | &.open {
95 | display: block;
96 | }
97 |
98 | p {
99 | font-size: 13px;
100 | color: $panel-body-p-color;
101 | }
102 |
103 | p.speed {
104 | font-size: 120%;
105 | font-weight: bold;
106 | float: right;
107 |
108 | @media (max-width: 1199px) {
109 | display: none;
110 | }
111 | }
112 |
113 | p.notice,
114 | p.info,
115 | p.warning,
116 | p.error {
117 | color: $panel-body-p-notice-color;
118 | }
119 |
120 | h3 {
121 | margin: 0 0 0.5em;
122 | }
123 |
124 | h3:first-child {
125 | margin-top: 0;
126 | }
127 |
128 | h3 + p {
129 | margin-top: 0;
130 | }
131 |
132 | a.dotted {
133 | text-decoration: none;
134 | border-bottom: 1px dotted;
135 | }
136 |
137 | &.pro-preview,
138 | .pro-preview {
139 | opacity: 0.5;
140 | }
141 | }
142 | }
143 |
--------------------------------------------------------------------------------
/src/client-s/css/admin-bar/_wipe-clear.scss:
--------------------------------------------------------------------------------
1 | /*[pro strip-from='lite']*/
2 |
3 | $clear-options-split-border-color: rgb(88, 88, 88);
4 |
5 | #wp-admin-bar-comet_cache-wipe,
6 | #wp-admin-bar-comet_cache-clear {
7 | > a {
8 | &::after {
9 | border: 0;
10 | padding: 0;
11 | content: ' ';
12 | width: 16px;
13 | height: 16px;
14 | line-height: 16px;
15 | vertical-align: middle;
16 | margin: -3px 0 0 5px;
17 | display: inline-block;
18 | }
19 | }
20 |
21 | &.-wipe {
22 | > a {
23 | &::after {
24 | content: url('../images/wipe.png');
25 | }
26 | }
27 | }
28 |
29 | &.-clear {
30 | > a {
31 | &::after {
32 | content: url('../images/clear.png');
33 | }
34 | }
35 | }
36 |
37 | &.-processing {
38 | > a {
39 | &::after {
40 | @include comet_cache-admin-bar-animation-spin;
41 |
42 | content: url('../images/spinner.png');
43 | }
44 | }
45 | }
46 | }
47 |
48 | #wp-admin-bar-comet_cache-clear-options-wrapper {
49 | &.-wrapper,
50 | .-container,
51 | .-container > div {
52 | margin: 0 !important;
53 | padding: 0 !important;
54 | display: block !important;
55 | white-space: normal !important;
56 | width: 100% !important;
57 | min-width: 100% !important;
58 | height: auto !important;
59 | line-height: normal !important;
60 | box-sizing: border-box !important;
61 | }
62 |
63 | &.-wrapper {
64 | padding: 1em !important;
65 |
66 | .-container {
67 | * {
68 | margin: 0;
69 | padding: 0;
70 | width: auto;
71 | height: auto;
72 | position: static;
73 | line-height: normal;
74 | box-sizing: border-box;
75 | }
76 |
77 | .-label {
78 | margin: 0 0 1em;
79 |
80 | &::after {
81 | border: 0;
82 | padding: 0;
83 | width: 16px;
84 | height: 16px;
85 | float: right;
86 | vertical-align: middle;
87 | display: inline-block;
88 | content: url('../images/clear.png');
89 | }
90 |
91 | .-text {
92 | opacity: 0.75;
93 | }
94 |
95 | &.-processing::after {
96 | @include comet_cache-admin-bar-animation-spin;
97 |
98 | content: url('../images/spinner.png');
99 | }
100 | }
101 |
102 | .-options {
103 | > li > a {
104 | &::before {
105 | padding-right: .5em;
106 | text-align: center;
107 | width: 1.28571429em;
108 | }
109 | }
110 |
111 | .-home-url-only {
112 | > a {
113 | @include sharkicon(home);
114 | }
115 | }
116 |
117 | .-current-url-only {
118 | > a {
119 | @include sharkicon(file-text-o);
120 | }
121 | }
122 |
123 | .-specific-url-only {
124 | > a {
125 | @include sharkicon(chain);
126 | }
127 | }
128 |
129 | .-opcache-only {
130 | > a {
131 | @include sharkicon(feat-layers);
132 | }
133 | }
134 |
135 | .-cdn-only {
136 | > a {
137 | @include sharkicon(cloud);
138 | }
139 | }
140 |
141 | .-transients-only {
142 | > a {
143 | @include sharkicon(feat-server);
144 | }
145 | }
146 | }
147 |
148 | .-spacer {
149 | min-width: 145px;
150 | }
151 | }
152 | }
153 | }
154 |
155 | #wp-admin-bar-comet_cache-clear-options {
156 | border-left: 1px solid $clear-options-split-border-color;
157 | border-right: 1px solid $clear-options-split-border-color;
158 |
159 | > a {
160 | @include sharkicon(chevron-down, after);
161 | }
162 |
163 | .-wrapper {
164 | .-container {
165 | .-spacer {
166 | min-width: 145px;
167 | }
168 | }
169 | }
170 | }
171 |
172 | /*[/pro]*/
173 |
--------------------------------------------------------------------------------
/src/includes/classes/Conflicts.php:
--------------------------------------------------------------------------------
1 | '.// Error notice.
96 | ' '.// Running one or more conflicting plugins at the same time.
97 | ' '.sprintf(__('%1$s is NOT running. A conflicting plugin, %2$s , is currently active. Please deactivate the %2$s plugin to clear this message.', SLUG_TD), esc_html($this_plugin_name), esc_html($conflicting_plugin_name)).
98 | '
'.
99 | '';
100 | });
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/src/includes/traits/Plugin/WcpDateArchiveUtils.php:
--------------------------------------------------------------------------------
1 | cacheKey('autoClearDateArchiveCache', [$post_id, $force]))) {
34 | return $counter; // Already did this.
35 | }
36 | $done = true; // Flag as having been done.
37 |
38 | if (!$this->options['enable']) {
39 | return $counter; // Nothing to do.
40 | }
41 | if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
42 | return $counter; // Nothing to do.
43 | }
44 | if (!$this->options['cache_clear_date_archives_enable']) {
45 | return $counter; // Nothing to do.
46 | }
47 | if (!is_dir($cache_dir = $this->cacheDir())) {
48 | return $counter; // Nothing to do.
49 | }
50 | $post_status = get_post_status($post_id); // Cache this.
51 |
52 | if ($post_status === 'draft' && isset($GLOBALS['pagenow'], $_POST['publish'])
53 | && is_admin() && $GLOBALS['pagenow'] === 'post.php' && current_user_can('publish_posts')
54 | && mb_strpos(wp_get_referer(), '/post-new.php') !== false
55 | ) {
56 | $post_status = 'publish'; // A new post being published now.
57 | }
58 | if (in_array($post_status, ['inherit', 'auto-draft'], true)) {
59 | return $counter; // Nothing to do. Note: `inherit` = revision.
60 | }
61 | if (in_array($post_status, ['draft', 'pending', 'future'], true) && !$force) {
62 | return $counter; // Nothing to do; i.e., NOT forcing in this case.
63 | }
64 | $date_archive_urls = []; // Initialize archive urls.
65 | $publish_time = get_post_time('U', true, $post_id);
66 |
67 | $Y = date('Y', $publish_time);
68 | $m = date('m', $publish_time);
69 | $j = date('j', $publish_time);
70 |
71 | if ($this->options['cache_clear_date_archives_enable'] === '1') {
72 | $date_archive_urls[sprintf(__('%1$s Date Archive', SLUG_TD), $Y)] = get_year_link($Y);
73 | $date_archive_urls[sprintf(__('%1$s/%2$s Date Archive', SLUG_TD), $Y, $m)] = get_month_link($Y, $m);
74 | $date_archive_urls[sprintf(__('%1$s/%2$s/%3$s Date Archive', SLUG_TD), $Y, $m, $j)] = get_day_link($Y, $m, $j);
75 | } elseif ($this->options['cache_clear_date_archives_enable'] === '2') {
76 | $date_archive_urls[sprintf(__('%1$s/%2$s Date Archive', SLUG_TD), $Y, $m)] = get_month_link($Y, $m);
77 | $date_archive_urls[sprintf(__('%1$s/%2$s/%3$s Date Archive', SLUG_TD), $Y, $m, $j)] = get_day_link($Y, $m, $j);
78 | } else { // Assume $this->options['cache_clear_date_archives_enable'] === '3'
79 | $date_archive_urls[sprintf(__('%1$s/%2$s/%3$s Date Archive', SLUG_TD), $Y, $m, $j)] = get_day_link($Y, $m, $j);
80 | }
81 | foreach ($date_archive_urls as $_label => $_url) {
82 | $_url_regex = $this->buildHostCachePathRegex($_url);
83 | $_url_counter = $this->clearFilesFromHostCacheDir($_url_regex);
84 | $counter += $_url_counter; // Add to overall counter.
85 |
86 | if ($_url_counter && $enqueued_notices < 100 && is_admin() && (!IS_PRO || $this->options['change_notifications_enable'])) {
87 | $this->enqueueNotice(sprintf(__('Found %1$s in the cache for %2$s; auto-clearing.', SLUG_TD), esc_html($this->i18nFiles($_url_counter)), esc_html($_label)), ['combinable' => true]);
88 | ++$enqueued_notices; // Increment enqueued notices counter.
89 | }
90 | } // unset($_label, $_url, $_url_regex, $_url_counter); // Housekeeping.
91 |
92 | return $counter;
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/src/includes/traits/Shared/UrlUtils.php:
--------------------------------------------------------------------------------
1 | -1) {
28 | if (${'//'} && $component === PHP_URL_SCHEME) {
29 | return $part = '//';
30 | }
31 | return $part = parse_url($url_uri_qsl, $component);
32 | } else {
33 | if (!is_array($parts = parse_url($url_uri_qsl))) {
34 | return $parts = [];
35 | }
36 | if (${'//'}) {
37 | $parts['scheme'] = '//';
38 | }
39 | return $parts;
40 | }
41 | }
42 |
43 | /**
44 | * Unparses a URL.
45 | *
46 | * @since 150821 Improving multisite compat.
47 | *
48 | * @param array $parts Input URL parts.
49 | *
50 | * @return string Unparsed URL in string format.
51 | */
52 | public function unParseUrl(array $parts)
53 | {
54 | $scheme = '';
55 | $host = '';
56 | $port = '';
57 | $user = '';
58 | $pass = '';
59 | $path = '';
60 | $query = '';
61 | $fragment = '';
62 |
63 | if (!empty($parts['scheme'])) {
64 | if ($parts['scheme'] === '//') {
65 | $scheme = $parts['scheme'];
66 | } else {
67 | $scheme = $parts['scheme'].'://';
68 | }
69 | }
70 | if (!empty($parts['host'])) {
71 | $host = $parts['host'];
72 | }
73 | if (!empty($parts['port'])) {
74 | $port = ':'.$parts['port'];
75 | }
76 | if (!empty($parts['user'])) {
77 | $user = $parts['user'];
78 | }
79 | if (!empty($parts['pass'])) {
80 | $pass = $parts['pass'];
81 | }
82 | if ($user || $pass) {
83 | $pass .= '@';
84 | }
85 | if (!empty($parts['path'])) {
86 | $path = '/'.ltrim($parts['path'], '/');
87 | }
88 | if (!empty($parts['query'])) {
89 | $query = '?'.$parts['query'];
90 | }
91 | if (!empty($parts['fragment'])) {
92 | $fragment = '#'.$parts['fragment'];
93 | }
94 | return $scheme.$user.$pass.$host.$port.$path.$query.$fragment;
95 | }
96 |
97 | /**
98 | * Is the current request over SSL?
99 | *
100 | * @since 150422 Rewrite.
101 | *
102 | * @return bool `TRUE` if the current request is over SSL.
103 | *
104 | * @note The return value of this function is cached to reduce overhead on repeat calls.
105 | */
106 | public function isSsl()
107 | {
108 | if (!is_null($is = &$this->staticKey('isSsl'))) {
109 | return $is; // Already cached this.
110 | }
111 | if (!empty($_SERVER['SERVER_PORT'])) {
112 | if ((integer) $_SERVER['SERVER_PORT'] === 443) {
113 | return $is = true;
114 | }
115 | }
116 | if (!empty($_SERVER['HTTPS'])) {
117 | if (filter_var($_SERVER['HTTPS'], FILTER_VALIDATE_BOOLEAN)) {
118 | return $is = true;
119 | }
120 | }
121 | if (!empty($_SERVER['HTTP_X_FORWARDED_PROTO'])) {
122 | if (strcasecmp((string) $_SERVER['HTTP_X_FORWARDED_PROTO'], 'https') === 0) {
123 | return $is = true;
124 | }
125 | }
126 | return $is = false;
127 | }
128 |
129 | /**
130 | * Current URL.
131 | *
132 | * @since 150821 Improving multisite compat.
133 | *
134 | * @return string Current URL.
135 | */
136 | public function currentUrl()
137 | {
138 | if (empty($_SERVER['HTTP_HOST']) || empty($_SERVER['REQUEST_URI'])) {
139 | return ''; // Not possible.
140 | }
141 | return ($this->isSsl() ? 'https://' : 'http://').$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'];
142 | }
143 | }
144 |
--------------------------------------------------------------------------------