Skip to content

Commit 7493071

Browse files
V4.0.0 (#330)
* Improve translation on Settings pages. * Fix test. * Login/Signup Popup Login Form. * Login/Signup Popup Register Form. * Login/Signup Popup add hCaptcha reset. * Login/Signup Popup update readme.txt. * Add CoBlocks integration. * Add CoBlocks integration. * Fix hash error preventing first sending of the form. * Make request.php test coverage 100%. * WPCS. * Make Migrations test coverage 100%. * Identify and fix change in the Siteverify Error Codes Table. * Add Enterprise params to System Info. * Check the Enterprise params before saving. * Show console errors on General page when updating hCaptcha API script. * Show console errors on General page when updating hCaptcha API script. * WPCS. * Update readme.txt. * Security and other updates of packages. * Fix CI tests. * Fix CI tests. * Fix CI tests. * Fix CI tests. * Fix CI tests. * Fix CI tests. * Fix CI tests. * Fix CI tests. * Fix CI tests. * Fix CI tests. * Update actions/cache to v4. * Fix CI tests. * Fix CI tests. * Fix CI tests. * Fix CI tests. * Fix CI tests. * Fix CI tests. * Fix CI tests. * Fix CI tests. * Fix integration tests on CI. * Fix integration tests on CI. * Update migrations to use 2-digit version numbers. * Fix Migrations tests. * Fix Settings layout for Chrome 122. * Fix Settings layout for Chrome 122. * Add Elementor Pro Login integration. * Fix tests. * Update readme.txt. * Fix CSP headers. * Fix Jetpack form styling. * WPCS. * Add Force hCaptcha check feature. * Add Force hCaptcha check to Jetpack. * Add Force hCaptcha check feature. * Update readme.txt. * Fix grammar and styling in readme.txt. * Add force argument to the shortcode and update readme.txt. * Fix tests. * Fix Jetpack tests. * WPCS. * ESLint. * Fix Jetpack tests. * Prevent submit when force widget was manually solved. * Prevent submit when force widget was manually solved. * Do not execute hCaptcha twice. * Fix Jest. * Tested with WooCommerce 8.6. * Tested with WooCommerce 8.6. * Fix Migrations test. * Fix Migrations test. * Add tracking info class. * WPCS. * Add registered report domain. * Change tracking event name. * Change tracking event name. * Add 3.10.0 migration. * Revert test change. * Update readme.txt according to new standards. * Add User-Agent header to TrackingInfo.php. * Fix error codes in request_verify. * Change event name to the custom one. * Fix fatal error with Formidable Forms 6.8.2. * Block Formidable hCaptcha settings. * Always add hcaptcha-widget. * Fix 40 tests after widget update. * WPCS. * WPCS. * Save hCaptcha events. * Update GH infrastructure. * Save hCaptcha events. * Save hCaptcha events. * Fix tests. * Use in CF7 the latest HCaptcha features. * Fix cf7-hcaptcha shortcode to save event form_id. * Create Events list page. * Create Events list page. * Date axis and scaling issues in Chart. * Date axis and scaling issues in Chart. * Make Chart responsive. * Tested with WordPress 6.5. * Rename EventsInfo class. * Rename EventsInfo class. * Improve language on Events page. * Create Forms page. * Create Forms page. * Create Forms page. * Block Forms page when Statistics switch is off. * Add Statistics settings section. * Add sample Foms Page image. * Add sample Events Page image. * Do not write statistics when switch is off. * Add collection switches. * Do not collect items if not selected. * Fix tests. * Shrink the tracking information. * Send tracking info on plugin update. * Fix test. * Add Enterprise to Tracking info. * Fix CSP issue. * Fix Tracking Info. * Store all class instances into repository. * Update readme.txt. * Flatten the tracking info. * Update changelog.txt. * Change custom event name. * Update readme.txt. * Update softprops/action-gh-release. * Fix Content Security Policy headers processing. * Fix test. * Raise the version to the latest released one. * Update changelog.txt and readme.txt. * Move migration to 4.0.0, add test. * Create Events table on migration only. Rename Tracking to Stats. * Fix test. * Fix test. * Fix test. * Fix test. * Fix test. * Fix test. * Fix test. * Fix test. * Fix test. * Add CSP headers filter. * Add actions and filters descriptions. * Remove deprecated code. * Replace tracking wording to statistics. * Add form arguments. * Update readme.txt. * Add force hCaptcha option. * Add force hCaptcha option. * Fix tests. * Fix force in shortcode. * Fix test. * Update readme.txt. * WPCS. * Fix issue with Divi Contact Form Helper plugin and File Upload field. * Use helper in hcaptcha-back-in-stock-notifier.js. * Use helper in hcaptcha-passster.js. * Use helper in hcaptcha-beaver-builder.js. * ESLint. * Update readme.txt. * Squeeze plugin stats. * Detect and use Pro account. * Add notifications for statistics new admin pages. * Fix test. * Add blinking of options mentioned in url hash. * Compact readme.txt. * Add blinking of options mentioned in url hash. * Add blinking of options mentioned in url hash. * Disable Enter in the search input on Integrations page. * Ignore 'recaptchacompat disabled' in displayed js console messages. * Ignore 'recaptchacompat disabled' in displayed js console messages. * Grammar. * Send statistics on turning on the switch. * Fix Force with Spectra. * ESLint. * Fix Force with Passster. * Fix Force with Passster. * Fix Force with Passster. * Fix Force with Beaver Builder. * Fix Force with Beaver Builder. * Fix Force with Passster. * Fix tests. * Fix Force with NF. * Fix jest. * Fix Force with NF. * Send license name in stats. * Send license name in stats. * Fix module issue and racing condition in Passter. * Fix module issue and racing condition in Back-In-Stock-Notifier. * Fix module issue and racing condition in Beaver Builder. * Do not add type="module" twice. * Fix module issue and racing condition in Ninja Forms. * Fix module issue and racing condition in Divi. * Fix jest. * Update readme.txt. * WC tested up to: 8.7. * Fix Force with wpDiscuz. * Fix Force with Support Candy. * Fix Force with Kadence. * Fix undefined message on Integrations after re-login. * Fix tests. * Fix tests. * WPCS. * WPCS. * Rework Otter to follow all modern features. * Update readme.txt. * Blur Custom and Enterprise sections with a Free account. * Do not save settings twice. * Allow using custom params with Free in admin only for educational purposes. * Add notification for Force and improve notification logic. * Do not check nonce in CF7 for not logged-in users. * Update readme.txt. * Add Custom Theme Editor. * Make SettingsBase test coverage 100%. * Make SettingsBase test coverage 100%. * Make SettingsBase test coverage 100%. * Make PluginSettingsBase test coverage 100%. * Make General test coverage 100%. * Make General test coverage 100%. * WPCS. * Make Integrations test coverage 100%. * Make Settings test coverage 100%. * Fix code for php 7.0. * Fix code for php 7.0. * Make SystemInfo test coverage 100%. * Make SystemInfo test coverage 100%. * Integration with Essential Addon Login. * Integration with Essential Addon Login. * Integration with Essential Addon Login. * Integration with Essential Addons Register. * Integration with Essential Addons Register. * Bump up version. * Update readme.txt * Apply suggestions from code review * Update readme.txt Co-authored-by: e271828- <e271828-@users.noreply.github.com> * Add stats screenshots. --------- Co-authored-by: e271828- <e271828-@users.noreply.github.com>
1 parent 05b03e6 commit 7493071

File tree

78 files changed

+5560
-557
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

78 files changed

+5560
-557
lines changed

.tests/js/assets-js-files/hcaptcha-beaver-builder.test.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,13 @@ describe( 'hCaptcha Beaver Builder', () => {
1212
};
1313

1414
beforeEach( () => {
15+
global.wp = {
16+
hooks: {
17+
addFilter: jest.fn(),
18+
applyFilters: jest.fn( ( hook, content ) => content ),
19+
},
20+
};
21+
1522
// Mock jQuery.ajaxPrefilter
1623
$.ajaxPrefilter = jest.fn( ( callback ) => {
1724
ajaxPrefilterCallback = callback;
@@ -49,4 +56,12 @@ describe( 'hCaptcha Beaver Builder', () => {
4956
expect( options.data ).not.toContain( 'hcaptcha_beaver_builder_nonce' );
5057
expect( options.data ).not.toContain( 'hcaptcha_login_nonce' );
5158
} );
59+
60+
test( 'does not append anything when data is not a string', () => {
61+
options.data = {};
62+
ajaxPrefilterCallback( options );
63+
expect( options.data ).not.toContain( 'h-captcha-response' );
64+
expect( options.data ).not.toContain( 'hcaptcha_beaver_builder_nonce' );
65+
expect( options.data ).not.toContain( 'hcaptcha_login_nonce' );
66+
} );
5267
} );

.tests/js/assets-js-files/hcaptcha-divi.test.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,14 @@ describe( 'hCaptcha ajaxStop binding', () => {
2727
$( document ).trigger( 'ajaxSuccess', [ xhr, settings ] );
2828
expect( hCaptchaBindEvents ).toHaveBeenCalledTimes( 1 );
2929
} );
30+
31+
test( 'hCaptchaBindEvents is not called when ajaxSuccess event is triggered with unexpected data', () => {
32+
const xhr = {};
33+
const settings = {};
34+
35+
// Unexpected object having data which is not a string.
36+
settings.data = {};
37+
$( document ).trigger( 'ajaxSuccess', [ xhr, settings ] );
38+
expect( hCaptchaBindEvents ).not.toHaveBeenCalled();
39+
} );
3040
} );

.tests/js/assets-js-files/hcaptcha-support-candy.test.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,13 @@ describe( 'hCaptcha ajaxStop binding', () => {
99
let hCaptchaBindEvents;
1010

1111
beforeEach( () => {
12+
global.wp = {
13+
hooks: {
14+
addFilter: jest.fn(),
15+
applyFilters: jest.fn( ( hook, content ) => content ),
16+
},
17+
};
18+
1219
hCaptchaBindEvents = jest.fn();
1320
global.hCaptchaBindEvents = hCaptchaBindEvents;
1421

.tests/js/assets-js-files/ncaptcha-nf.test.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,13 @@ describe( 'Ninja Forms hCaptcha', () => {
1414
let controller;
1515

1616
beforeEach( () => {
17+
global.wp = {
18+
hooks: {
19+
addFilter: jest.fn(),
20+
applyFilters: jest.fn( ( hook, content ) => content ),
21+
},
22+
};
23+
1724
require( '../../../assets/js/hcaptcha-nf.js' );
1825

1926
// Execute DOMContentLoaded event

.tests/js/hcaptcha/hcaptcha.test.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,13 @@ describe( 'HCaptcha', () => {
1616

1717
beforeEach( () => {
1818
hCaptcha = new HCaptcha();
19+
20+
global.wp = {
21+
hooks: {
22+
addFilter: jest.fn(),
23+
applyFilters: jest.fn( ( hook, content ) => content ),
24+
},
25+
};
1926
} );
2027

2128
test( 'GenerateID', () => {

.tests/php/integration/AAAMainTest.php

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
use ReflectionException;
4242
use stdClass;
4343
use tad\FunctionMocker\FunctionMocker;
44+
use HCaptcha\Admin\PluginStats;
4445
use HCaptcha\Admin\Events\Events;
4546

4647
/**
@@ -648,6 +649,7 @@ public function test_get_api_src() {
648649
'image_host' => 'imgs-cn1.hcaptcha.com',
649650
'report_api' => 'reportapi-cn1.hcaptcha.com',
650651
'sentry' => 'cn1.hcaptcha.com',
652+
'license' => 'pro',
651653
]
652654
);
653655

@@ -862,6 +864,7 @@ function delayedLoad() {
862864
// phpcs:ignore WordPress.WP.AlternativeFunctions.json_encode_json_encode
863865
'config_params' => json_encode( $config_params ),
864866
'delay' => - 100,
867+
'license' => 'pro',
865868
]
866869
);
867870

@@ -878,7 +881,7 @@ function delayedLoad() {
878881

879882
$script = wp_scripts()->registered['hcaptcha'];
880883
self::assertSame( HCAPTCHA_URL . '/assets/js/apps/hcaptcha.js', $script->src );
881-
self::assertSame( [], $script->deps );
884+
self::assertSame( [ 'wp-hooks' ], $script->deps );
882885
self::assertSame( HCAPTCHA_VERSION, $script->ver );
883886
self::assertSame( $expected_extra, $script->extra );
884887

@@ -907,7 +910,7 @@ function delayedLoad() {
907910

908911
$script = wp_scripts()->registered['hcaptcha'];
909912
self::assertSame( HCAPTCHA_URL . '/assets/js/apps/hcaptcha.js', $script->src );
910-
self::assertSame( [], $script->deps );
913+
self::assertSame( [ 'wp-hooks' ], $script->deps );
911914
self::assertSame( HCAPTCHA_VERSION, $script->ver );
912915
self::assertSame( $expected_extra, $script->extra );
913916

@@ -1073,7 +1076,10 @@ static function () use ( &$activate ) {
10731076

10741077
// Test with hCaptcha plugin not active.
10751078
$subject->load_modules();
1076-
$expected_loaded_classes = [];
1079+
$expected_loaded_classes = [
1080+
PluginStats::class,
1081+
Events::class,
1082+
];
10771083
$loaded_classes = $this->get_protected_property( $subject, 'loaded_classes' );
10781084

10791085
self::assertSame( $expected_loaded_classes, array_keys( $loaded_classes ) );

.tests/php/integration/Admin/NotificationsTest.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,30 @@ public function test_init( bool $empty_keys ) {
9494
'text' => 'Get started',
9595
],
9696
],
97+
'statistics' => [
98+
'title' => 'Events statistics and Forms admin page',
99+
'message' => '<a href="http://test.test/wp-admin/options-general.php?page=hcaptcha&tab=general#statistics_1" target="_blank">Turn on</a> events statistics and <a href="http://test.test/wp-admin/options-general.php?page=hcaptcha&tab=forms" target="_blank">see</a> how your forms are used.',
100+
'button' => [
101+
'url' => 'http://test.test/wp-admin/options-general.php?page=hcaptcha&tab=general#statistics_1',
102+
'text' => 'Turn on stats',
103+
],
104+
],
105+
'events_page' => [
106+
'title' => 'Events admin page',
107+
'message' => '<a href="http://test.test/wp-admin/options-general.php?page=hcaptcha&tab=general#statistics_1" target="_blank">Turn on</a> events statistics and <a href="https://dashboard.hcaptcha.com/?r=wp&utm_source=wordpress&utm_medium=wpplugin&utm_campaign=not" target="_blank">upgrade to Pro</a> to <a href="http://test.test/wp-admin/options-general.php?page=hcaptcha&tab=events" target="_blank">see</a> complete statistics on form events.',
108+
'button' => [
109+
'url' => 'http://test.test/wp-admin/options-general.php?page=hcaptcha&tab=general#statistics_1',
110+
'text' => 'Turn on stats',
111+
],
112+
],
113+
'force' => [
114+
'title' => 'Force hCaptcha',
115+
'message' => 'Force hCaptcha check before submitting the form and simplify the user experience.',
116+
'button' => [
117+
'url' => 'http://test.test/wp-admin/options-general.php?page=hcaptcha&tab=general#force_1',
118+
'text' => 'Turn on force',
119+
],
120+
],
97121
];
98122

99123
if ( ! $empty_keys ) {

.tests/php/integration/MainPluginFileTest.php

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,6 @@ public function test_main_file_content() {
6060
self::assertTrue( function_exists( 'hcaptcha_get_verify_message_html' ) );
6161

6262
// functions.php was required.
63-
self::assertTrue( function_exists( 'hcap_form' ) );
64-
self::assertTrue( function_exists( 'hcap_form_display' ) );
6563
self::assertTrue( function_exists( 'hcap_shortcode' ) );
6664
self::assertTrue( shortcode_exists( 'hcaptcha' ) );
6765
}

.tests/php/integration/Migrations/MigrationsTest.php

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
namespace HCaptcha\Tests\Integration\Migrations;
99

10+
use HCaptcha\Admin\Events\Events;
1011
use HCaptcha\Migrations\Migrations;
1112
use HCaptcha\Tests\Integration\HCaptchaWPTestCase;
1213
use Mockery;
@@ -111,7 +112,11 @@ public function test_migrate() {
111112
'woocommerce_wishlists_status' => [],
112113
'wpforms_status' => [ 'form' ],
113114
'wpforo_status' => [],
115+
'force' => [],
114116
'custom_themes' => [],
117+
'statistics' => [],
118+
'collect_ip' => [],
119+
'collect_ua' => [],
115120
'_network_wide' => [],
116121
];
117122

@@ -180,4 +185,52 @@ public function test_migrate_360_when_wpforms_status_not_set() {
180185

181186
self::assertSame( $option, get_option( 'hcaptcha_settings', [] ) );
182187
}
188+
189+
/**
190+
* Test migrate_4_0_0().
191+
*
192+
* @return void
193+
* @throws ReflectionException ReflectionException.
194+
*/
195+
public function test_migrate_4_0_0() {
196+
global $wpdb;
197+
198+
$method = 'migrate_4_0_0';
199+
$subject = Mockery::mock( Migrations::class )->makePartial();
200+
$table_name = Events::TABLE_NAME;
201+
$charset_collate = $wpdb->get_charset_collate();
202+
$actual_query = '';
203+
$expected_query = "CREATE TABLE IF NOT EXISTS $wpdb->prefix$table_name (
204+
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
205+
source VARCHAR(256) NOT NULL,
206+
form_id VARCHAR(20) NOT NULL,
207+
ip VARCHAR(39) NOT NULL,
208+
user_agent VARCHAR(256) NOT NULL,
209+
uuid VARCHAR(36) NOT NULL,
210+
error_codes VARCHAR(256) NOT NULL,
211+
date_gmt DATETIME NOT NULL,
212+
PRIMARY KEY (id),
213+
KEY source (source),
214+
KEY form_id (form_id),
215+
KEY hcaptcha_id (source, form_id),
216+
KEY ip (ip),
217+
KEY uuid (uuid),
218+
KEY date_gmt (date_gmt)
219+
) $charset_collate;";
220+
221+
add_filter(
222+
'dbdelta_queries',
223+
static function ( $queries ) use ( &$actual_query ) {
224+
$actual_query = $queries;
225+
226+
return $queries;
227+
}
228+
);
229+
230+
$this->set_method_accessibility( $subject, $method );
231+
232+
$subject->$method();
233+
234+
self::assertSame( array_filter( explode( ';', $expected_query ) ), $actual_query );
235+
}
183236
}

.tests/php/unit/HCaptchaTestCase.php

Lines changed: 88 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -293,10 +293,6 @@ protected function get_test_settings(): array {
293293
[],
294294
'recaptcha_compat_off' =>
295295
[],
296-
'custom_theme_params' => '{
297-
"theme": "dark",
298-
"size": "compact"
299-
}',
300296
'config_params' => '',
301297
'whitelisted_ips' => '4444444.777.2
302298
220.45.45.1
@@ -541,6 +537,15 @@ protected function get_test_general_form_fields(): array {
541537
'default' => General::MODE_LIVE,
542538
'helper' => 'Select live or test mode. In test mode, predefined keys are used.',
543539
],
540+
'force' => [
541+
'label' => 'Force hCaptcha',
542+
'type' => 'checkbox',
543+
'section' => General::SECTION_APPEARANCE,
544+
'options' => [
545+
'on' => 'Force hCaptcha',
546+
],
547+
'helper' => 'Force hCaptcha check before submit.',
548+
],
544549
'custom_themes' => [
545550
'label' => 'Custom Themes',
546551
'type' => 'checkbox',
@@ -561,6 +566,19 @@ protected function get_test_general_form_fields(): array {
561566
)
562567
),
563568
],
569+
'custom_prop' => [
570+
'label' => 'Property',
571+
'type' => 'select',
572+
'options' => [],
573+
'section' => 'custom',
574+
'helper' => 'Select custom theme property.',
575+
],
576+
'custom_value' => [
577+
'label' => 'Value',
578+
'type' => 'text',
579+
'section' => 'custom',
580+
'helper' => 'Set property value.',
581+
],
564582
'config_params' => [
565583
'label' => 'Config Params',
566584
'type' => 'textarea',
@@ -680,6 +698,32 @@ protected function get_test_general_form_fields(): array {
680698
'step' => 100,
681699
'helper' => 'Delay time for loading the hCaptcha API script. Any negative value will prevent the API script from loading until user interaction: mouseenter, click, scroll or touch. This significantly improves Google Pagespeed Insights score.',
682700
],
701+
'statistics' => [
702+
'label' => 'Statistics',
703+
'type' => 'checkbox',
704+
'section' => General::SECTION_STATISTICS,
705+
'options' => [
706+
'on' => 'Enable Statistics',
707+
],
708+
'helper' => 'By turning the statistics on, you agree to the collection of non-personal data to improve the plugin.',
709+
],
710+
'collect_ip' => [
711+
'label' => 'Collection',
712+
'type' => 'checkbox',
713+
'section' => General::SECTION_STATISTICS,
714+
'options' => [
715+
'on' => 'Collect IP',
716+
],
717+
'helper' => 'Allow collecting of IP addresses from which forms were sent.',
718+
],
719+
'collect_ua' => [
720+
'type' => 'checkbox',
721+
'section' => General::SECTION_STATISTICS,
722+
'options' => [
723+
'on' => 'Collect User Agent',
724+
],
725+
'helper' => 'Allow collecting of User Agent headers of users sending forms.',
726+
],
683727
];
684728

685729
if ( ! ( function_exists( 'is_multisite' ) && is_multisite() ) ) {
@@ -873,6 +917,14 @@ protected function get_test_integrations_form_fields(): array {
873917
'login' => 'Login',
874918
],
875919
],
920+
'essential_addons_status' => [
921+
'label' => 'Essential Addons',
922+
'type' => 'checkbox',
923+
'options' => [
924+
'login' => 'Login',
925+
'register' => 'Register',
926+
],
927+
],
876928
'fluent_status' =>
877929
[
878930
'label' => 'Fluent Forms',
@@ -1197,4 +1249,36 @@ protected function get_test_integrations_form_fields(): array {
11971249
],
11981250
];
11991251
}
1252+
1253+
/**
1254+
* Sort fields. First, by enabled status, then by label.
1255+
*
1256+
* @param array $fields Fields.
1257+
*
1258+
* @return array
1259+
*/
1260+
public function sort_fields( array $fields ): array {
1261+
uasort(
1262+
$fields,
1263+
static function ( $a, $b ) {
1264+
$a_disabled = $a['disabled'] ?? false;
1265+
$b_disabled = $b['disabled'] ?? false;
1266+
1267+
$a_label = strtolower( $a['label'] ?? '' );
1268+
$b_label = strtolower( $b['label'] ?? '' );
1269+
1270+
if ( $a_disabled === $b_disabled ) {
1271+
return $a_label <=> $b_label;
1272+
}
1273+
1274+
if ( ! $a_disabled && $b_disabled ) {
1275+
return -1;
1276+
}
1277+
1278+
return 1;
1279+
}
1280+
);
1281+
1282+
return $fields;
1283+
}
12001284
}

0 commit comments

Comments
 (0)