From 15a89a140f2c07563e8b4c5331dfe0ce2b2a17fd Mon Sep 17 00:00:00 2001 From: Cooper Dalrymple Date: Fri, 5 Jun 2026 17:44:26 -0500 Subject: [PATCH] Added Gravity Forms Addon --- composer.json | 2 +- composer.lock | 8 +- inc/abstract-location.php | 28 ++---- inc/class-api.php | 18 ++++ inc/class-settings.php | 10 +++ inc/gravityforms/class-addon.php | 142 ++++++++++++++++++++++++++++++ inc/location/class-login-page.php | 5 +- ogre-captcha.php | 27 +++++- package.json | 2 +- 9 files changed, 210 insertions(+), 32 deletions(-) create mode 100644 inc/gravityforms/class-addon.php diff --git a/composer.json b/composer.json index 3358a42..4dea866 100644 --- a/composer.json +++ b/composer.json @@ -1,7 +1,7 @@ { "$schema": "https://getcomposer.org/schema.json", "name": "cleverogre/ogre-captcha", - "version": "1.0.1", + "version": "1.1.0", "title": "Ogre CAPTCHA", "description": "Protect your site with CAPTCHA", "author": "CleverOgre", diff --git a/composer.lock b/composer.lock index cc39dbd..2896b32 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "1daff9d4452a2ff8f159fea23468a225", + "content-hash": "49f5e6f919f33ce6a3edc2992620a64a", "packages": [ { "name": "cleverogre/plugin-framework", @@ -59,7 +59,7 @@ "source": { "type": "git", "url": "git@git.cleverogre.com:cleverogre/plugin-update-checker.git", - "reference": "010b7cf90b5df60d6d98256d48594ae423b951b7" + "reference": "b05c3dd4cf01f45544358671018dd5b5851cd079" }, "require": { "composer/installers": "~1.0", @@ -69,7 +69,7 @@ "default-branch": true, "type": "wordpress-plugin", "extra": { - "installer-name": "update-plugin-checker" + "installer-name": "plugin-update-checker" }, "license": [ "MIT" @@ -90,7 +90,7 @@ "theme updates", "wordpress" ], - "time": "2026-06-05T20:17:06+00:00" + "time": "2026-06-05T22:05:11+00:00" }, { "name": "cleverogre/updatepulse-updater", diff --git a/inc/abstract-location.php b/inc/abstract-location.php index e2e94c2..4a2eded 100644 --- a/inc/abstract-location.php +++ b/inc/abstract-location.php @@ -20,9 +20,6 @@ defined('ABSPATH') || exit; abstract class Location { use Singleton; - public const ERROR_EMPTY_TOKEN = 'empty_captcha_token'; - public const ERROR_INVALID_CAPTCHA = 'invalid_captcha_result'; - protected string $name; protected function __construct(string $name) { @@ -54,31 +51,22 @@ abstract class Location { Widget::render(); } - public function process(WP_Error $errors):void { - if (!Settings::is_connected()) return; - - $token = Widget::get_token(); - if (empty($token)) { - $errors->add(self::ERROR_EMPTY_TOKEN, Plugin::__('Error: Please complete CAPTCHA verification.')); - return; - } - - if (!API::verify($token)) { - $errors->add(self::ERROR_INVALID_CAPTCHA, Plugin::__('Error: Your answer was incorrect - please try again.')); - return; - } + public function process(WP_Error|null $errors = null):void { + API::process(Widget::get_token(), $errors); } protected function print_errors(WP_Error $errors):void { if (!$errors->has_errors()) return; - ob_start(); - echo ''; + + ob_start(); + echo ''; wp_die(ob_get_clean()); } diff --git a/inc/class-api.php b/inc/class-api.php index a39f756..cc39646 100644 --- a/inc/class-api.php +++ b/inc/class-api.php @@ -10,12 +10,17 @@ namespace Ogre\Captcha; +use Ogre\Captcha as Plugin; use Ogre\Captcha\Settings; +use WP_Error; defined('ABSPATH') || exit; final class API { + public const ERROR_EMPTY_TOKEN = 'empty_captcha_token'; + public const ERROR_INVALID_CAPTCHA = 'invalid_captcha_result'; + private static function transaction(string $url, array $data):array|string|bool { $ch = curl_init($url); curl_setopt($ch, CURLOPT_POSTFIELDS, wp_json_encode($data)); @@ -52,4 +57,17 @@ final class API { return is_bool($result) ? $result : false; } + public static function process(string $token, WP_Error|null $errors = null): WP_Error { + if (is_null($errors)) $errors = new WP_Error(); + if (!Settings::is_connected()) return $errors; + + if (empty($token)) { + $errors->add(self::ERROR_EMPTY_TOKEN, Plugin::__('Please complete CAPTCHA verification.')); + } else if (!API::verify($token)) { + $errors->add(self::ERROR_INVALID_CAPTCHA, Plugin::__('Your answer was incorrect - please try again.')); + } + + return $errors; + } + } diff --git a/inc/class-settings.php b/inc/class-settings.php index 33210f7..68e99a7 100644 --- a/inc/class-settings.php +++ b/inc/class-settings.php @@ -44,6 +44,16 @@ final class Settings { return $data; } + private static function set(string $key, $value = null):void { + $data = self::get(); + if (is_null($value) && isset($data[$key])) { + unset($data[$key]); + } else { + $data[$key] = $value; + } + update_option(Plugin::get_id(), $data); + } + private static function is_checked(string $name, string $value):bool { return in_array($value, (array) self::get($name)); } diff --git a/inc/gravityforms/class-addon.php b/inc/gravityforms/class-addon.php new file mode 100644 index 0000000..64c0837 --- /dev/null +++ b/inc/gravityforms/class-addon.php @@ -0,0 +1,142 @@ +_version = Plugin::get_version(); + $this->_slug = Plugin::get_id(); + $this->_path = sprintf( + '%1$s/%1$s.php', + Plugin::get_id() + ); + $this->_full_path = Plugin::get_file(); + $this->_title = sprintf( + Plugin::__('%s Add-On'), + Plugin::get_title() + ); + $this->_short_title = Plugin::get_title(); + } + + public function init() { + add_filter('gform_submit_button', [$this, 'submit_button'], 10, 2); + add_filter('gform_validation', [$this, 'validation'], 10, 2); + } + + public function get_menu_icon() { + return 'gform-icon--lock'; + } + + public function plugin_settings_fields() { + return [ + [ + 'title' => esc_html(sprintf( + Plugin::__('%s Settings'), + Plugin::get_title() + )), + 'description' => sprintf( + Plugin::__('Looking to configure your CAPTCHA connection? You can find the settings on this page.'), + esc_url(Settings::get_url()) + ), + 'fields' => [ + [ + 'label' => sprintf( + Plugin::esc_html__('Enable %s'), + Plugin::get_title() + ), + 'type' => 'checkbox', + 'name' => 'enabled', + 'choices' => [ + [ + 'label' => Plugin::esc_html__('Enable CAPTCHA on all forms by default.'), + 'name' => 'enabled', + ] + ] + ] + ] + ] + ]; + } + + public function form_settings_fields($form) { + return [ + [ + 'title' => esc_html(sprintf( + Plugin::__('%s Settings'), + Plugin::get_title() + )), + 'fields' => [ + [ + 'type' => 'checkbox', + 'name' => 'disabled', + 'choices' => [ + [ + 'label' => Plugin::esc_html__('Disable CAPTCHA for this form.'), + 'name' => 'disabled', + ] + ] + ] + ] + ] + ]; + } + + public function is_enabled(array|null $form = null): bool { + $plugin_enabled = (bool) $this->get_plugin_setting('enabled'); + if (is_null($form) || !$plugin_enabled) return $plugin_enabled; + + $form_settings = $this->get_form_settings($form); + $form_disabled = (bool) rgar($form_settings, 'disabled'); + return !$form_disabled; + } + + public function submit_button(string $button_input, array $form): string { + if (!Settings::is_connected() || !$this->is_enabled($form)) return $button_input; + ob_start(); + Widget::render(); + return ob_get_clean() . $button_input; + } + + public function validation(array $validation_result, string $context): array { + if ($context != 'form-submit') return $validation_result; + + if (!Settings::is_connected() || !$this->is_enabled(rgar($validation_result, 'form'))) return $validation_result; + + $errors = API::process(Widget::get_token()); + if ($errors->has_errors()) { + $validation_result['is_valid'] = false; + } + + // TODO: Mark as spam (optional) + return $validation_result; + } + +} diff --git a/inc/location/class-login-page.php b/inc/location/class-login-page.php index 8d46ac0..6be5c9f 100644 --- a/inc/location/class-login-page.php +++ b/inc/location/class-login-page.php @@ -10,6 +10,7 @@ namespace Ogre\Captcha\Location; +use Ogre\Captcha\API; use Override; use Ogre\Captcha\Location; use Ogre\Captcha\Settings; @@ -42,8 +43,8 @@ final class LoginPage extends Location { return array_merge( $shake_error_codes, [ - self::ERROR_EMPTY_TOKEN, - self::ERROR_INVALID_CAPTCHA, + API::ERROR_EMPTY_TOKEN, + API::ERROR_INVALID_CAPTCHA, ] ); } diff --git a/ogre-captcha.php b/ogre-captcha.php index 0717355..fcb8f9e 100644 --- a/ogre-captcha.php +++ b/ogre-captcha.php @@ -6,14 +6,14 @@ * @author cleverogre * @copyright 2026 CleverOgre * @license GLP-3.0-or-later - * @version 1.0.1 + * @version 1.1.0 * @since 1.0.0 * * @wordpress-plugin * Plugin Name: Ogre CAPTCHA * Plugin URI: https://git.cleverogre.com/cleverogre/ogre-captcha/ * Description: Protect your site with CAPTCHA - * Version: 1.0.1 + * Version: 1.1.0 * Requires at least: 6.0 * Requires PHP: 8.2 * Author: CleverOgre @@ -33,6 +33,9 @@ namespace Ogre; use Ogre\Captcha\Settings; +use Ogre\Captcha\GravityForms\Addon; +use GFAddOn; +use Override; defined('ABSPATH') || exit; @@ -44,6 +47,10 @@ final class Captcha extends Plugin { return is_plugin_active('woocommerce/woocommerce.php'); } + public static function is_gravityforms_active():bool { + return is_plugin_active('gravityforms/gravityforms.php'); + } + protected function __construct() { parent::__construct(); @@ -59,18 +66,22 @@ final class Captcha extends Plugin { 'inc/location/class-post-password-form.php', 'inc/location/class-registration-page.php', ]); - - add_action('plugins_loaded', [$this, 'load_woocommerce'], 9, 0); } + #[Override] protected function enable():void { parent::enable(); add_filter('plugin_action_links_' . self::get_basename(), [$this, 'action_links']); + add_action('plugins_loaded', [$this, 'load_woocommerce'], 2, 0); + add_action('gform_loaded', [$this, 'load_gravityforms'], 5, 0); } + #[Override] protected function disable():void { parent::disable(); remove_filter('plugin_action_links_' . self::get_basename(), [$this, 'action_links']); + remove_action('plugins_loaded', [$this, 'load_woocommerce'], 2); + remove_action('gform_loaded', [$this, 'load_gravityforms'], 5); } public function action_links(array $links):array { @@ -95,6 +106,14 @@ final class Captcha extends Plugin { ]); } + public function load_gravityforms():void { + if (!self::is_gravityforms_active() || !method_exists('GFForms', 'include_addon_framework')) return; + + require_once('inc/gravityforms/class-addon.php'); + + GFAddOn::register(Addon::class); + } + } Captcha::instance(); diff --git a/package.json b/package.json index 3a2ade7..4384338 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "$schema": "https://www.schemastore.org/package.json", "name": "cleverogre/ogre-captcha", - "version": "1.0.1", + "version": "1.1.0", "title": "Ogre CAPTCHA", "description": "Protect your site with CAPTCHA", "author": "CleverOgre",