From 06e80fa0740edc57f75ac8b8c05de0eb8afad3ad Mon Sep 17 00:00:00 2001 From: AntonV1211 Date: Wed, 15 Apr 2026 18:33:57 +0700 Subject: [PATCH 1/2] Mod. BloomForms. Editing the integration with BloomForms --- inc/cleantalk-pluggable.php | 8 + .../Antispam/Integrations/BloomForms.php | 17 +- .../IntegrationsByHook/TestBloomForms.php | 225 ++++++++++++++++++ 3 files changed, 249 insertions(+), 1 deletion(-) create mode 100644 tests/Antispam/IntegrationsByHook/TestBloomForms.php diff --git a/inc/cleantalk-pluggable.php b/inc/cleantalk-pluggable.php index a33b90857..a849f85fa 100644 --- a/inc/cleantalk-pluggable.php +++ b/inc/cleantalk-pluggable.php @@ -1744,6 +1744,14 @@ class_exists('Cleantalk\Antispam\Integrations\CleantalkInternalForms') ) { return 'invoicing'; } + + //Bloom skip - has the direct integration + if ( + apbct_is_plugin_active('bloom/bloom.php') && + Post::equal('action', 'bloom_subscribe') + ) { + return 'Bloom skip - has the direct integration'; + } } else { /*****************************************/ /* Here is non-ajax requests skipping */ diff --git a/lib/Cleantalk/Antispam/Integrations/BloomForms.php b/lib/Cleantalk/Antispam/Integrations/BloomForms.php index 4281f0f44..f8e43e1dc 100644 --- a/lib/Cleantalk/Antispam/Integrations/BloomForms.php +++ b/lib/Cleantalk/Antispam/Integrations/BloomForms.php @@ -10,7 +10,22 @@ public function getDataForChecking($argument) { Cookie::$force_alt_cookies_global = true; - return ct_gfa(apply_filters('apbct__filter_post', $_POST)); + $filtered_post = apply_filters('apbct__filter_post', $_POST); + $nickname = ''; + + // Extract nickname from subscribe_data_array if it exists + if ( ! empty($_POST['subscribe_data_array']) && is_string($_POST['subscribe_data_array']) ) { + // Remove escaping from quoted JSON + $data_to_decode = wp_unslash($_POST['subscribe_data_array']); + if ( is_string($data_to_decode) ) { + $subscribe_data = json_decode($data_to_decode, true); + if ( is_array($subscribe_data) && ! empty($subscribe_data['name']) ) { + $nickname = sanitize_text_field($subscribe_data['name']); + } + } + } + + return ct_gfa_dto($filtered_post, '', $nickname)->getArray(); } public function doBlock($message) diff --git a/tests/Antispam/IntegrationsByHook/TestBloomForms.php b/tests/Antispam/IntegrationsByHook/TestBloomForms.php new file mode 100644 index 000000000..5b0fcfa95 --- /dev/null +++ b/tests/Antispam/IntegrationsByHook/TestBloomForms.php @@ -0,0 +1,225 @@ +integration = new BloomForms(); + } + + protected function tearDown(): void + { + // Clean up global state + $_POST = []; + Post::getInstance()->variables = []; + parent::tearDown(); + } + + /** + * Test extraction of nickname from subscribe_data_array with valid JSON + */ + public function testGetDataForCheckingWithValidJsonName() + { + $_POST['action'] = 'bloom_subscribe'; + $_POST['subscribe_data_array'] = '{"list_id":123,"name":"TestUser","email":"test@example.com"}'; + + $result = $this->integration->getDataForChecking(null); + + $this->assertIsArray($result); + $this->assertEquals('TestUser', $result['nickname']); + } + + /** + * Test extraction of nickname from subscribe_data_array with escaped JSON (real-world case) + */ + public function testGetDataForCheckingWithEscapedJsonName() + { + $_POST['action'] = 'bloom_subscribe'; + $_POST['subscribe_data_array'] = '{\"list_id\":113164156,\"account_name\":\"test@example\",\"service\":\"mailerlite\",\"name\":\"qwe123\",\"email\":\"test@example.com\",\"page_id\":245335,\"optin_id\":\"optin_40\",\"last_name\":\"\",\"ip_address\":\"true\"}'; + + $result = $this->integration->getDataForChecking(null); + + $this->assertIsArray($result); + $this->assertEquals('qwe123', $result['nickname']); + } + + /** + * Test with empty name in subscribe_data_array + */ + public function testGetDataForCheckingWithEmptyName() + { + $_POST['action'] = 'bloom_subscribe'; + $_POST['subscribe_data_array'] = '{"list_id":123,"name":"","email":"test@example.com"}'; + + $result = $this->integration->getDataForChecking(null); + + $this->assertIsArray($result); + $this->assertEquals('', $result['nickname']); + } + + /** + * Test without subscribe_data_array field + */ + public function testGetDataForCheckingWithoutSubscribeDataArray() + { + $_POST['action'] = 'bloom_subscribe'; + $_POST['email'] = 'test@example.com'; + + $result = $this->integration->getDataForChecking(null); + + $this->assertIsArray($result); + $this->assertEquals('', $result['nickname']); + } + + /** + * Test with invalid JSON in subscribe_data_array + */ + public function testGetDataForCheckingWithInvalidJson() + { + $_POST['action'] = 'bloom_subscribe'; + $_POST['subscribe_data_array'] = 'not a valid json string'; + + $result = $this->integration->getDataForChecking(null); + + $this->assertIsArray($result); + $this->assertEquals('', $result['nickname']); + } + + /** + * Test with special characters in name + */ + public function testGetDataForCheckingWithSpecialCharactersInName() + { + $_POST['action'] = 'bloom_subscribe'; + $_POST['subscribe_data_array'] = '{"name":"O\'Brien Müller","email":"special@example.com"}'; + + $result = $this->integration->getDataForChecking(null); + + $this->assertIsArray($result); + $this->assertStringContainsString("O'Brien", $result['nickname']); + $this->assertStringContainsString('Müller', $result['nickname']); + } + + /** + * Test with name containing only whitespace + */ + public function testGetDataForCheckingWithWhitespaceName() + { + $_POST['action'] = 'bloom_subscribe'; + $_POST['subscribe_data_array'] = '{"name":" ","email":"test@example.com"}'; + + $result = $this->integration->getDataForChecking(null); + + $this->assertIsArray($result); + // sanitize_text_field trims whitespace, so it should be empty + $this->assertEquals('', $result['nickname']); + } + + /** + * Test with numeric name value + */ + public function testGetDataForCheckingWithNumericName() + { + $_POST['action'] = 'bloom_subscribe'; + $_POST['subscribe_data_array'] = '{"name":12345,"email":"test@example.com"}'; + + $result = $this->integration->getDataForChecking(null); + + $this->assertIsArray($result); + // Numeric value should be converted to string + $this->assertEquals('12345', $result['nickname']); + } + + /** + * Test with null name value in JSON + */ + public function testGetDataForCheckingWithNullName() + { + $_POST['action'] = 'bloom_subscribe'; + $_POST['subscribe_data_array'] = '{"name":null,"email":"test@example.com"}'; + + $result = $this->integration->getDataForChecking(null); + + $this->assertIsArray($result); + $this->assertEquals('', $result['nickname']); + } + + /** + * Test with missing name field in JSON + */ + public function testGetDataForCheckingWithMissingNameField() + { + $_POST['action'] = 'bloom_subscribe'; + $_POST['subscribe_data_array'] = '{"email":"test@example.com","list_id":123}'; + + $result = $this->integration->getDataForChecking(null); + + $this->assertIsArray($result); + $this->assertEquals('', $result['nickname']); + } + + /** + * Test with empty POST data + */ + public function testGetDataForCheckingWithEmptyPost() + { + $_POST = []; + + $result = $this->integration->getDataForChecking(null); + + $this->assertIsArray($result); + $this->assertEquals('', $result['nickname']); + } + + /** + * Test with array value for subscribe_data_array (should not decode) + */ + public function testGetDataForCheckingWithArraySubscribeData() + { + $_POST['action'] = 'bloom_subscribe'; + $_POST['subscribe_data_array'] = ['name' => 'TestUser', 'email' => 'test@example.com']; + + $result = $this->integration->getDataForChecking(null); + + $this->assertIsArray($result); + // Array is not a string, so nickname extraction should not work + $this->assertEquals('', $result['nickname']); + } + + /** + * Test with double-escaped JSON + */ + public function testGetDataForCheckingWithDoubleEscapedJson() + { + $_POST['action'] = 'bloom_subscribe'; + // Double escaped - after wp_unslash should become valid JSON + $_POST['subscribe_data_array'] = '{\\\"name\\\":\\\"DoubleEscaped\\\",\\\"email\\\":\\\"test@example.com\\\"}'; + + $result = $this->integration->getDataForChecking(null); + + $this->assertIsArray($result); + // This depends on how wp_unslash handles double escaping + } + + /** + * Test email extraction from subscribe_data_array + */ + public function testGetDataForCheckingEmailExtraction() + { + $_POST['action'] = 'bloom_subscribe'; + $_POST['subscribe_data_array'] = '{"name":"TestUser","email":"bloom@example.com"}'; + + $result = $this->integration->getDataForChecking(null); + + $this->assertIsArray($result); + $this->assertArrayHasKey('email', $result); + } +} From 13d3fbdd28bee939bc1109a53670a8edaffaacf0 Mon Sep 17 00:00:00 2001 From: AntonV1211 Date: Wed, 15 Apr 2026 18:36:44 +0700 Subject: [PATCH 2/2] Fix. BloomForms. Edit duplicate passes --- inc/cleantalk-pluggable.php | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/inc/cleantalk-pluggable.php b/inc/cleantalk-pluggable.php index a849f85fa..f2fa74442 100644 --- a/inc/cleantalk-pluggable.php +++ b/inc/cleantalk-pluggable.php @@ -1450,7 +1450,7 @@ function apbct_is_skip_request($ajax = false, $ajax_message_obj = array()) apbct_is_plugin_active('bloom/bloom.php') && Post::get('action') === 'bloom_subscribe' ) { - return 'Bloom'; + return 'Bloom skip - has the direct integration'; } // Ajax Search Lite - these requests will be caught by search form protection @@ -1744,14 +1744,6 @@ class_exists('Cleantalk\Antispam\Integrations\CleantalkInternalForms') ) { return 'invoicing'; } - - //Bloom skip - has the direct integration - if ( - apbct_is_plugin_active('bloom/bloom.php') && - Post::equal('action', 'bloom_subscribe') - ) { - return 'Bloom skip - has the direct integration'; - } } else { /*****************************************/ /* Here is non-ajax requests skipping */