Skip to content

Commit b6694e6

Browse files
committed
Fix. Integrations. GiveWP now has bot detector scripts in iframes.
1 parent 4beeecc commit b6694e6

6 files changed

Lines changed: 445 additions & 21 deletions

File tree

cleantalk.php

Lines changed: 3 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
Domain Path: /i18n
1212
*/
1313

14+
use Cleantalk\Antispam\ScriptsIntegration\CleantalkScriptsIntegrator;
1415
use Cleantalk\Antispam\ProtectByShortcode;
1516
use Cleantalk\ApbctWP\Activator;
1617
use Cleantalk\ApbctWP\AdminNotices;
@@ -597,27 +598,8 @@ function apbct_write_js_errors($data)
597598

598599
// Public actions
599600
if ( ! is_admin() && ! apbct_is_ajax() && ! apbct_is_customize_preview() ) {
600-
if (
601-
apbct_is_plugin_active('fluentformpro/fluentformpro.php') &&
602-
(
603-
apbct_is_in_uri('ff_landing=') ||
604-
(
605-
// Load scripts for logged in users if constant is defined
606-
apbct_is_user_logged_in() &&
607-
(defined('APBCT_FF_JS_SCRIPTS_LOAD') &&
608-
APBCT_FF_JS_SCRIPTS_LOAD == true)
609-
)
610-
)
611-
) {
612-
add_action('wp_head', function () {
613-
echo '<script data-pagespeed-no-defer="" src="'
614-
. APBCT_URL_PATH
615-
. '/js/apbct-public-bundle.min.js'
616-
. '?ver=' . APBCT_VERSION . '" id="ct_public_functions-js"></script>';
617-
echo '<script src="' . APBCT_BOT_DETECTOR_SCRIPT_URL . '?ver='
618-
. APBCT_VERSION . '" async id="ct_bot_detector-js" data-wp-strategy="async"></script>';
619-
}, 100);
620-
}
601+
$sci = new CleantalkScriptsIntegrator();
602+
$sci->run();
621603

622604
SFWUpdateHelper::processSFWOutdatedError($apbct);
623605

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
<?php
2+
3+
namespace Cleantalk\Antispam\ScriptsIntegration;
4+
5+
class CleantalkScriptsIntegrator
6+
{
7+
/**
8+
* List of plugins selected for inline script integration,
9+
* indexed by their corresponding WordPress hook name.
10+
*
11+
* @var ScriptIntegrationPlugin[]
12+
*/
13+
public $plugins_loaded = [];
14+
15+
/**
16+
* Executes the integration process.
17+
*
18+
* This method:
19+
* - Retrieves available integrations
20+
* - Filters plugins that should be loaded
21+
* - Registers WordPress hooks to execute plugin integration logic
22+
*
23+
* @return void
24+
*/
25+
public function run()
26+
{
27+
$integrations = $this->getIntegrations();
28+
29+
$this->plugins_loaded = !empty($integrations)
30+
? $this->getPluginsToInline($integrations)
31+
: [];
32+
33+
if (!empty($this->plugins_loaded)) {
34+
foreach ($this->plugins_loaded as $_hook => $plugin) {
35+
if ($plugin instanceof ScriptIntegrationPlugin) {
36+
add_action($_hook, function () use ($plugin) {
37+
$plugin->integrate();
38+
}, 100);
39+
}
40+
}
41+
}
42+
}
43+
44+
/**
45+
* Filters plugins that are eligible for inline script integration.
46+
*
47+
* A plugin is included only if:
48+
* - It is active
49+
* - It matches the current URI context
50+
* - It passes additional runtime checks
51+
*
52+
* Each hook can only be assigned to one plugin (first match wins).
53+
*
54+
* @param ScriptIntegrationPlugin[] $integrations List of available plugin integrations.
55+
* @return ScriptIntegrationPlugin[] Filtered plugins indexed by hook name.
56+
*/
57+
public function getPluginsToInline($integrations)
58+
{
59+
$plugins_loaded = [];
60+
61+
foreach ($integrations as $plugin) {
62+
if (
63+
$plugin->is_plugin_active &&
64+
$plugin->is_in_uri &&
65+
$plugin->additional_checks_passed
66+
) {
67+
if (!isset($plugins_loaded[$plugin->hook_name])) {
68+
$plugins_loaded[$plugin->hook_name] = $plugin;
69+
}
70+
}
71+
}
72+
73+
return $plugins_loaded;
74+
}
75+
76+
/**
77+
* Returns a list of all available plugin integrations.
78+
*
79+
* Each integration defines:
80+
* - Activation rules
81+
* - Context conditions (URI, environment, etc.)
82+
* - Hook target for script injection
83+
*
84+
* @return ScriptIntegrationPlugin[]
85+
*/
86+
public function getIntegrations()
87+
{
88+
try {
89+
$integrations = [
90+
new GiveWPScript(),
91+
new FluentFormScript(),
92+
];
93+
} catch (\Exception $e) {
94+
$integrations = [];
95+
}
96+
97+
return $integrations;
98+
}
99+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php
2+
3+
namespace Cleantalk\Antispam\ScriptsIntegration;
4+
5+
class FluentFormScript extends ScriptIntegrationPlugin
6+
{
7+
public $hook_name = 'wp_head';
8+
public $plugin_file = 'fluentformpro/fluentformpro.php';
9+
public $uri_chunk = 'ff_landing=';
10+
11+
public function integrate()
12+
{
13+
echo '<script data-pagespeed-no-defer="" src="'
14+
. APBCT_URL_PATH
15+
. '/js/apbct-public-bundle.min.js'
16+
. '?ver=' . APBCT_VERSION . '" id="ct_public_functions-js"></script>';
17+
echo '<script src="' . APBCT_BOT_DETECTOR_SCRIPT_URL . '?ver='
18+
. APBCT_VERSION . '" async id="ct_bot_detector-js" data-wp-strategy="async"></script>';
19+
}
20+
21+
public function additionalChecks()
22+
{
23+
return $this->is_in_uri || (
24+
function_exists('apbct_is_user_logged_in') &&
25+
apbct_is_user_logged_in() &&
26+
(defined('APBCT_FF_JS_SCRIPTS_LOAD') && APBCT_FF_JS_SCRIPTS_LOAD == true)
27+
);
28+
}
29+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
namespace Cleantalk\Antispam\ScriptsIntegration;
4+
5+
class GiveWPScript extends ScriptIntegrationPlugin
6+
{
7+
public $hook_name = 'givewp_donation_form_enqueue_scripts';
8+
public $plugin_file = 'give/give.php';
9+
public $uri_chunk = 'givewp-route=donation-form-view';
10+
11+
public function integrate()
12+
{
13+
// Bot detector
14+
if ( apbct__is_bot_detector_enabled() && ! apbct_bot_detector_scripts_exclusion()) {
15+
// Attention! Skip old enqueue way for external script.
16+
wp_enqueue_script(
17+
'ct_bot_detector',
18+
APBCT_BOT_DETECTOR_SCRIPT_URL,
19+
[],
20+
APBCT_VERSION,
21+
array(
22+
'in_footer' => true,
23+
'strategy' => 'async'
24+
)
25+
);
26+
}
27+
}
28+
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
<?php
2+
3+
namespace Cleantalk\Antispam\ScriptsIntegration;
4+
5+
abstract class ScriptIntegrationPlugin
6+
{
7+
public $is_plugin_active;
8+
public $is_in_uri;
9+
public $additional_checks_passed;
10+
11+
public $plugin_file;
12+
public $uri_chunk;
13+
public $hook_name;
14+
15+
public function __construct()
16+
{
17+
if (
18+
!isset($this->plugin_file) ||
19+
!is_string($this->plugin_file) ||
20+
!isset($this->uri_chunk) ||
21+
!is_string($this->uri_chunk) ||
22+
!isset($this->hook_name) ||
23+
!is_string($this->hook_name)
24+
) {
25+
throw new \Exception('Plugin file, URI chunk and hook name must be set');
26+
}
27+
28+
$this->is_plugin_active = $this->isPluginActive($this->plugin_file);
29+
$this->is_in_uri = $this->isInUri($this->uri_chunk);
30+
$this->additional_checks_passed = $this->additionalChecks();
31+
}
32+
33+
/**
34+
* Executes the plugin integration logic.
35+
*
36+
* This method must be implemented by each concrete integration class
37+
* and is responsible for registering scripts, hooks, or other behaviors.
38+
*
39+
* @return void
40+
*/
41+
abstract public function integrate();
42+
43+
/**
44+
* Checks whether a given WordPress plugin is active.
45+
*
46+
* @param string $plugin_file Path to the plugin main file.
47+
* @return bool True if the plugin is active, false otherwise.
48+
*/
49+
public function isPluginActive($plugin_file)
50+
{
51+
return apbct_is_plugin_active($plugin_file);
52+
}
53+
54+
/**
55+
* Checks whether the current request URI contains a specific substring.
56+
*
57+
* @param string $uri_chunk URI fragment to search for in the current request URI.
58+
* @return bool True if the URI fragment is found, false otherwise.
59+
*/
60+
public function isInUri($uri_chunk)
61+
{
62+
return apbct_is_in_uri($uri_chunk);
63+
}
64+
65+
/**
66+
* Performs additional runtime checks required for plugin activation.
67+
*
68+
* This method can be overridden in child classes to implement
69+
* custom validation logic.
70+
*
71+
* @return bool True if all additional checks pass, false otherwise.
72+
*/
73+
public function additionalChecks()
74+
{
75+
return true;
76+
}
77+
}

0 commit comments

Comments
 (0)