Skip to content

Commit

Permalink
#32 Support Divi Contact Forms (#120)
Browse files Browse the repository at this point in the history
* #32 Support Divi Contact Forms

* #32 Divi: Improve and use existing mutation-observer script

* Add option to frcaptcha_enqueue_widget_scripts to force-add mutation observer when needed

* Make mutation-observer script more bulletproof:
 * Ensure to load after main scripts, so the friendly captcha functions are always available
 * Load after DOMload
 * Also make async/defer like the main script

* Remove custom script.js

* #32 Divi: Fix Notice in Admin

* #32 Init Mutationobserver without waiting for scripts
  • Loading branch information
amenk committed Apr 24, 2024
1 parent 4c86382 commit e2037e7
Show file tree
Hide file tree
Showing 7 changed files with 236 additions and 18 deletions.
12 changes: 11 additions & 1 deletion friendly-captcha/includes/core.php
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ class FriendlyCaptcha_Plugin {
public static $option_pb_login_integration_active_name = "frcaptcha_pb_login_integration_active";
public static $option_pb_register_integration_active_name = "frcaptcha_pb_register_integration_active";
public static $option_pb_reset_password_integration_active_name = "frcaptcha_pb_reset_password_integration_active";
public static $option_divi_integration_active_name = "frcaptcha_divi_integration_active";

public static $option_widget_language_name = "frcaptcha_widget_language";
public static $option_widget_dark_theme_active_name = "frcaptcha_widget_dark_theme_active";
Expand Down Expand Up @@ -222,6 +223,11 @@ public function get_pb_reset_password_active() {
return get_option(FriendlyCaptcha_Plugin::$option_pb_reset_password_integration_active_name) == 1;
}

public function get_divi_active() {
return get_option(FriendlyCaptcha_Plugin::$option_divi_integration_active_name) == 1;
}


/* Widget options */

public function get_widget_language() {
Expand Down Expand Up @@ -379,6 +385,10 @@ public function get_global_puzzle_endpoint_active() {
}

if (FriendlyCaptcha_Plugin::$instance->get_pb_reset_password_active()) {
require plugin_dir_path( __FILE__ ) . '../modules/profile-builder/profile_builder_reset_password.php';
require plugin_dir_path(__FILE__) . '../modules/profile-builder/profile_builder_reset_password.php';
}

if (FriendlyCaptcha_Plugin::$instance->get_divi_active()) {
require plugin_dir_path( __FILE__ ) . '../modules/divi/divi.php';
}
// }
17 changes: 17 additions & 0 deletions friendly-captcha/includes/settings.php
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,11 @@ function frcaptcha_settings_init() {
FriendlyCaptcha_Plugin::$option_pb_reset_password_integration_active_name
);

register_setting(
FriendlyCaptcha_Plugin::$option_group,
FriendlyCaptcha_Plugin::$option_divi_integration_active_name
);

/*Widget settings */
register_setting(
FriendlyCaptcha_Plugin::$option_group,
Expand Down Expand Up @@ -552,6 +557,18 @@ function frcaptcha_settings_init() {
)
);

add_settings_field(
'frcaptcha_settings_divi_integration_field',
'Divi Theme Contact Form', 'frcaptcha_settings_field_callback',
'friendly_captcha_admin',
'frcaptcha_integrations_settings_section',
array(
"option_name" => FriendlyCaptcha_Plugin::$option_divi_integration_active_name,
"description" => "Enable Friendly Captcha and replace ReCaptcha in the <a href=\"https://www.elegantthemes.com/gallery/divi//\" target=\"_blank\">Divi Theme</a> contact form.<br /><strong>Important:</strong> Please choose 'FriendlyCaptcha verification' as spam protection in each individual Divi contact form.",
"type" => "checkbox"
)
);

/* Widget settings section */

// Section
Expand Down
88 changes: 88 additions & 0 deletions friendly-captcha/modules/divi/divi.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
<?php

add_filter('et_core_get_third_party_components', array('frcaptcha_divi_load_addon', 'register'));
add_filter('et_core_api_spam_enabled_providers', array('frcaptcha_divi_load_addon', 'enable'));
add_filter('option_et_core_api_spam_options', array('frcaptcha_divi_load_addon', 'injectAccount'));
add_action('init', array('frcaptcha_divi_load_addon', 'fakeToken'));
add_filter('do_shortcode_tag', array('frcaptcha_divi_load_addon', 'addWidget'), 10, 2);

class frcaptcha_divi_load_addon
{
const SUPPORTED_SHORTCODES = ['et_pb_contact_form'];

const INSERT_BEFORE = '<button type="submit"';

public static function register($instances = [], $group = '')
{
if ($group !== 'api/spam' && $group !== '') {
return $instances;
}

require_once 'frcaptcha_divi_core_addon.php';

$instances['frcaptcha'] = new frcaptcha_divi_core_addon();

return $instances;
}

public static function enable($_names_by_slug) {
$plugin = FriendlyCaptcha_Plugin::$instance;

if (!$plugin->is_configured() or !$plugin->get_divi_active()) {
return;
}

$_names_by_slug['third-party']['frcaptcha'] = 'FriendlyCaptcha verification';
return $_names_by_slug;
}

public static function injectAccount($value, $option = 'et_core_api_spam_options')
{
$plugin = FriendlyCaptcha_Plugin::$instance;

if (!$plugin->is_configured() or !$plugin->get_divi_active()) {
return;
}

$value = maybe_unserialize($value);
$value['accounts']['frcaptcha']['default'] = [
'site_key' => 'default',
'secret_key' => 'default'
];

return $value;

}

public static function addWidget($output, $tag = null)
{
if (!in_array($tag, self::SUPPORTED_SHORTCODES)) {
return $output;
}

$plugin = FriendlyCaptcha_Plugin::$instance;

if (!$plugin->is_configured() or !$plugin->get_divi_active()) {
return;
}

$output = str_replace(self::INSERT_BEFORE,
frcaptcha_generate_widget_tag_from_plugin(FriendlyCaptcha_Plugin::$instance) . self::INSERT_BEFORE,
$output
);

return $output;
}

/**
* Fake Token in POST
*
* @see \ET_Builder_Module_Type_WithSpamProtection::is_spam_submission
*/
public static function fakeToken()
{
if (isset($_POST['frc-captcha-solution'])) {
$_POST['token'] = $_POST['frc-captcha-solution'];
}
}
}
95 changes: 95 additions & 0 deletions friendly-captcha/modules/divi/frcaptcha_divi_core_addon.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
<?php

class frcaptcha_divi_core_addon extends ET_Core_API_Spam_Provider {
public $name = 'FriendlyCaptcha';

/**
* @inheritDoc
*/
public $slug = 'frcaptcha';

public $custom_fields = null; // avoid notice from \ET_Core_API_Email_Providers::_initialize which expects this field

public function __construct( $owner = 'frcaptcha', $account_name = '', $api_key = '' ) {
parent::__construct( $owner, $account_name, $api_key );

$this->_add_actions_and_filters();
}

protected function _add_actions_and_filters() {
if ( ! is_admin() && ! et_core_is_fb_enabled() ) {
add_action( 'wp_enqueue_scripts', array( $this, 'action_wp_enqueue_scripts' ) );
}
}

public function action_wp_enqueue_scripts() {
$plugin = FriendlyCaptcha_Plugin::$instance;

if ( !$plugin->is_configured() ) {
return;
}

if ( ! $this->is_enabled() ) {
return;
}

frcaptcha_enqueue_widget_scripts(true);

wp_dequeue_script('et-core-api-spam-recaptcha');
}

public function is_enabled() {
$has_frcaptcha_module = true;

if ( class_exists( 'ET_Dynamic_Assets' ) ) {
$et_dynamic_module_framework = et_builder_dynamic_module_framework();
$is_dynamic_framework_enabled = et_builder_is_frontend() && 'on' === $et_dynamic_module_framework;
$is_dynamic_css_enabled = et_builder_is_frontend() && et_use_dynamic_css();

if ( $is_dynamic_framework_enabled && $is_dynamic_css_enabled ) {
$et_dynamic_assets = ET_Dynamic_Assets::init();
$saved_shortcodes = $et_dynamic_assets->get_saved_page_shortcodes();
$frcaptcha_modules = array( 'et_pb_contact_form', 'et_pb_signup' );
$has_frcaptcha_module = ! empty( array_intersect( $saved_shortcodes, $frcaptcha_modules ) );
}
}

return $has_frcaptcha_module;
}

public function verify_form_submission() {
$plugin = FriendlyCaptcha_Plugin::$instance;

if ( !$plugin->is_configured() ) {
return array(
'success' => true,
'score' => 100000,
);
}

if ( ! $this->is_enabled() ) {
return array(
'success' => true,
'score' => 100000,
);
}

$solution = et_()->array_get_sanitized( $_POST, 'token' );

$plugin = FriendlyCaptcha_Plugin::$instance;
$verification = frcaptcha_verify_captcha_solution($solution, $plugin->get_sitekey(), $plugin->get_api_key());

if ( $verification["success"] ) {
return array(
'success' => true,
'score' => 100000,
);
} else {
return 'Captcha error';
}
}

public function get_account_fields() {
return array();
}
}
1 change: 1 addition & 0 deletions friendly-captcha/modules/divi/index.php
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<?php // Silence is golden.
30 changes: 17 additions & 13 deletions friendly-captcha/public/mutation-observer.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
(function () {
function findCaptchaElements(node) {
return node.querySelectorAll(".frc-captcha");
if (node.querySelectorAll) {
return node.querySelectorAll(".frc-captcha");
} else {
return [];
}
}

function setupCaptchaElements(node) {
Expand Down Expand Up @@ -28,21 +32,21 @@
for (let m = 0; m < mutationList.length; m++) {
const mutation = mutationList[m];

if (mutation.type === "childList") {
// We only care about new nodes being added
const nodes = mutation.addedNodes;
const nodes = mutation.addedNodes;

for (let n = 0; n < nodes.length; n++) {
setupCaptchaElements(nodes[n]);
}
for (let n = 0; n < nodes.length; n++) {
setupCaptchaElements(nodes[n]);
}
}
});

// Start observing the document body for changes
observer.observe(document.body, {
attributes: false,
childList: true,
subtree: false,
});
function init() {
// Start observing the document body for changes
observer.observe(document.body, {
attributes: false,
childList: true,
subtree: true,
})};

init();
})();
11 changes: 7 additions & 4 deletions friendly-captcha/public/widgets.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?php

function frcaptcha_enqueue_widget_scripts() {
function frcaptcha_enqueue_widget_scripts($forceMutationObserver = false) {
$plugin = FriendlyCaptcha_Plugin::$instance;

if ( !$plugin->is_configured() ) {
Expand All @@ -25,7 +25,7 @@ function frcaptcha_enqueue_widget_scripts() {
true
);

if ( $plugin->get_enable_mutation_observer() ) {
if ( $forceMutationObserver || $plugin->get_enable_mutation_observer() ) {
wp_enqueue_script( 'friendly-captcha-mutation-observer',
plugin_dir_url( __FILE__ ) . 'mutation-observer.js',
array(),
Expand Down Expand Up @@ -61,7 +61,10 @@ function frcaptcha_transform_friendly_captcha_script_tags( $tag, $handle, $src )
if ( 'friendly-captcha-widget-fallback' == $handle) {
return str_replace( '<script', '<script async defer nomodule', $tag );
}

if ( 'friendly-captcha-mutation-observer' == $handle) {
return str_replace( '<script', '<script async defer', $tag );
}

return $tag;
}

Expand All @@ -76,7 +79,7 @@ function frcaptcha_generate_widget_tag_from_plugin($plugin) {
$extra_attributes = "";
$global = $plugin->get_global_puzzle_endpoint_active();
$eu = $plugin->get_eu_puzzle_endpoint_active();

if ($global && $eu) {
$extra_attributes = "data-puzzle-endpoint=\"https://eu-api.friendlycaptcha.eu/api/v1/puzzle,https://api.friendlycaptcha.com/api/v1/puzzle\"";
} else if ($eu) {
Expand Down

0 comments on commit e2037e7

Please sign in to comment.