Skip to content

Commit e375743

Browse files
committed
fix(connect): premium flips on at connect time; upsell links reach the connect tab (#71 #72) + 2.4.1
store_cloud_credentials() now marks the API status active instead of only clearing the cache: its only caller is the connect flow, right after a successful token exchange, so the key is known-good and is_premium() should not wait for a lazy revalidation while the user is watching their freshly connected site do nothing. Dashboard widget deep link used a #tab-cloud hash the settings page ignores (it only reads ?tab=cloud); the Statistics upsell sent people off-site to /pricing instead of the in-admin connect CTA.
1 parent 45f33d4 commit e375743

5 files changed

Lines changed: 26 additions & 8 deletions

File tree

admin/partials/dashboard-widget.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@
7575
<p>
7676
<strong><?php esc_html_e('Want more intelligence?', 'webdecoy'); ?></strong>
7777
<?php esc_html_e('Connect to WebDecoy Cloud for IP reputation, VPN detection, and cross-site threat data.', 'webdecoy'); ?>
78-
<a href="<?php echo esc_url(admin_url('admin.php?page=webdecoy#tab-cloud')); ?>">
78+
<a href="<?php echo esc_url(admin_url('admin.php?page=webdecoy&tab=cloud')); ?>">
7979
<?php esc_html_e('Learn more', 'webdecoy'); ?>
8080
</a>
8181
</p>

admin/partials/statistics-page.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -246,8 +246,8 @@
246246
<div class="webdecoy-cloud-upsell">
247247
<h3><?php esc_html_e('Want deeper insights?', 'webdecoy'); ?></h3>
248248
<p><?php esc_html_e('WebDecoy Cloud provides IP reputation scoring, VPN/proxy detection, geographic analysis, and indefinite data retention. Local data is automatically cleaned up after 30 days.', 'webdecoy'); ?></p>
249-
<a href="https://webdecoy.com/pricing" class="button button-primary" target="_blank" rel="noopener">
250-
<?php esc_html_e('Explore WebDecoy Cloud', 'webdecoy'); ?>
249+
<a href="<?php echo esc_url(admin_url('admin.php?page=webdecoy&tab=cloud')); ?>" class="button button-primary">
250+
<?php esc_html_e('Connect to WebDecoy Cloud', 'webdecoy'); ?>
251251
</a>
252252
</div>
253253
<?php endif; ?>

changelog.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
*** WebDecoy Bot Detection Changelog ***
22

3+
= 2.4.1 - 2026-08-17 =
4+
* Fixed: cloud features switch on immediately after one-click connect. The connection itself succeeded, but the premium status stayed off until a later background revalidation, so the JS verification token and cloud reporting were silently inactive at the exact moment you had just connected.
5+
* Fixed: the dashboard widget's "Learn more" link landed on the Protection tab instead of the WebDecoy Cloud tab.
6+
* Changed: the Statistics page upsell now opens the in-admin Cloud connect tab instead of leaving your site for the pricing page.
7+
38
= 2.4.0 - 2026-07-30 =
49
* Added: filter rules can read the WebDecoy edge validator's verdict through new edge.* fields — edge.class, edge.clearance, edge.present, plus the shorthands edge.verified / edge.crawler / edge.script / edge.browser. edge.class is one of: verified (an identity Cloudflare attested, such as Googlebot — never degrade these), crawler (says it is a crawler, unproven), script (an HTTP client library, not a browser), or browser (nothing non-human fired). Matching this was already possible as req.header("x-wd-class") because the plugin forwards every request header into the rule context, but nothing told you the header existed or what its values meant, so nobody used it. The Rules screen now lists the fields and explains them. Absence is deliberately not a class: if the validator is not in front of a request, edge.present is false and every edge.* condition is false, which means "no information" rather than "human" — a rule using these decides whether to serve someone less, so guessing would be the wrong default. A value we do not recognise is ignored rather than passed through. Safe to use for blocking, throttling, logging and metering; not safe for serving different page content on a cacheable URL, because Cloudflare's cache key ignores this header outside Enterprise plans, so the first cached version would be served to everyone including Googlebot — the Rules screen says so too.
510

readme.txt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ Donate link: https://webdecoy.com
44
Tags: bot detection, security, spam protection, woocommerce, ai bots
55
Requires at least: 6.1
66
Tested up to: 7.0
7-
Stable tag: 2.4.0
7+
Stable tag: 2.4.1
88
Requires PHP: 7.4
99
License: GPLv2 or later
1010
License URI: https://www.gnu.org/licenses/gpl-2.0.html
@@ -222,6 +222,11 @@ The bundled good-bot list (sdk/src/GoodBotList.php) stores a documentation URL f
222222

223223
== Changelog ==
224224

225+
= 2.4.1 =
226+
* Fixed: cloud features switch on immediately after one-click connect. The connection itself succeeded, but the premium status stayed off until a later background revalidation, so the JS verification token and cloud reporting were silently inactive at the exact moment you had just connected.
227+
* Fixed: the dashboard widget's "Learn more" link landed on the Protection tab instead of the WebDecoy Cloud tab.
228+
* Changed: the Statistics page upsell now opens the in-admin Cloud connect tab instead of leaving your site for the pricing page.
229+
225230
= 2.4.0 =
226231
* Added: filter rules can read what the WebDecoy edge validator concluded about a request, using new edge.* fields: edge.class, edge.clearance, edge.present, and the shorthands edge.verified / edge.crawler / edge.script / edge.browser. edge.class is one of: verified (an identity Cloudflare attested, such as Googlebot, never degrade these), crawler (says it is a crawler, unproven), script (an HTTP client library, not a browser), or browser (nothing non-human fired). This was always matchable as req.header("x-wd-class"), but nothing said so; the Rules screen now documents the fields and what each value means. If the validator is not in front of a request, edge.present is false and every edge.* condition is false. That means "no information", not "human". Safe for blocking, throttling, logging and metering; the Rules screen also explains why you should not use it to serve different page content on a cacheable URL.
227232

webdecoy.php

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* Plugin Name: WebDecoy Bot Detection
44
* Plugin URI: https://webdecoy.com/wordpress
55
* Description: Protect your WordPress site from bots, spam, and carding attacks with WebDecoy's advanced threat detection.
6-
* Version: 2.4.0
6+
* Version: 2.4.1
77
* Requires at least: 6.1
88
* Requires PHP: 7.4
99
* Author: WebDecoy
@@ -41,7 +41,7 @@ function str_starts_with(string $haystack, string $needle): bool
4141
}
4242

4343
// Plugin constants
44-
define('WEBDECOY_VERSION', '2.4.0');
44+
define('WEBDECOY_VERSION', '2.4.1');
4545
define('WEBDECOY_PLUGIN_FILE', __FILE__);
4646
define('WEBDECOY_PLUGIN_DIR', plugin_dir_path(__FILE__));
4747
define('WEBDECOY_PLUGIN_URL', plugin_dir_url(__FILE__));
@@ -3300,8 +3300,16 @@ public function store_cloud_credentials(string $api_key, string $site_key, strin
33003300
$this->options['api_key'] = $this->is_encrypted($api_key) ? $this->decrypt_value($api_key) : $api_key;
33013301
}
33023302

3303-
// Force a fresh API status check on next use now that creds changed.
3304-
$this->clear_api_status_cache();
3303+
// The only caller is the connect flow, which reaches here immediately
3304+
// after a successful token exchange against the API — the key is
3305+
// known-good right now. Mark the status active instead of merely
3306+
// clearing the cache: with only a clear, is_premium() stays false
3307+
// until something happens to trigger a revalidation, which keeps the
3308+
// JS verification token and violation reporting off at the exact
3309+
// moment the user just connected and is watching. (update_options_raw
3310+
// above already fired the option hook that clears the cache, so this
3311+
// set is what survives.)
3312+
$this->set_api_status_cache('active');
33053313
}
33063314

33073315
/**

0 commit comments

Comments
 (0)