Skip to content

Add Shield silentCAPTCHA integration#58

Open
paulgoodchild wants to merge 3 commits intoGravityKit:developfrom
paulgoodchild:develop
Open

Add Shield silentCAPTCHA integration#58
paulgoodchild wants to merge 3 commits intoGravityKit:developfrom
paulgoodchild:develop

Conversation

@paulgoodchild
Copy link
Copy Markdown

@paulgoodchild paulgoodchild commented Mar 24, 2026

Add Shield silentCAPTCHA Integration

Summary

This PR adds an optional Shield silentCAPTCHA integration to Gravity Forms Zero Spam.

The goal is simple:

  • let sites use Shield as an extra server-side spam signal
  • keep the existing Zero Spam behavior intact
  • make the settings understandable at both the global and per-form level
  • avoid breaking submissions if Shield is missing, disabled, or returns something unexpected

Where To Look

Start here:

  • includes/class-gf-zero-spam-addon.php
  • includes/class-gf-zero-spam-shield-silent-captcha.php

class-gf-zero-spam-addon.php only does the wiring:

  • loads the new Shield integration class
  • initializes it
  • lets it add plugin settings
  • lets it normalize Shield settings before save

class-gf-zero-spam-shield-silent-captcha.php contains the actual implementation:

  • settings
  • saved-value normalization
  • global default / per-form override logic
  • Shield verdict handling
  • admin UI messages

Useful methods to review first:

  • filter_entry_is_spam()
  • maybe_abort_submission()
  • normalize_plugin_settings()
  • normalize_form_settings()
  • get_effective_form_setting_value()
  • resolve_shield_bot_verdict()
  • render_plugin_status_field()
  • render_form_status_field()

Main Behavior

Runtime

Shield is only used as an extra spam signal.

  • if Gravity Forms already marked the entry as spam, we leave that alone
  • if Shield returns strict true, we mark the entry as spam
  • if Shield returns false, null, throws, or is unavailable, we do not block the submission

This is intentionally fail-open. A broken or missing Shield integration should not interrupt form submissions.

Save and Continue follows the same rule:

  • if something already asked to abort, we do not interfere
  • if Shield returns strict true, we abort draft creation
  • otherwise we leave the request alone

If Gravity Forms cannot record the spam filter directly, the integration falls back to adding an entry note. That is why the class tracks flagged form IDs during the request.

Default And Override Logic

The plugin setting is the default.

  • if a form has no saved Shield value, it inherits the global default
  • if a form has a saved Shield value, that value overrides the global default

This is based on whether the form key exists, not just whether the value is on or off.

That matters because:

  • missing form key = inherit
  • saved 0 = explicit override off
  • saved 1 = explicit override on

There is no separate inherit/override control in the UI. The current form toggle is still a single on/off control.

That means:

  • untouched forms inherit the global setting
  • once a form settings page is saved, the displayed value becomes that form's explicit override

Settings And Save Handling

Both the global and per-form Shield settings use:

  • the real visible toggle
  • a hidden persist field
  • an HTML status/help field

The hidden persist field exists so a disabled Shield toggle does not accidentally save as off just because the browser did not submit it.

The Shield status field is an HTML field, not a fake text field, so Gravity Forms does not try to validate it like a normal saved setting.

Admin UI Behavior

Global Settings

The global setting is labelled as the default for forms.

The message under it changes by Shield state:

  • unavailable
  • threshold is zero
  • normal help

Per-Form Settings

The per-form tooltip now explains two things:

  • whether the form is currently inheriting or overriding the global default
  • the current Shield state for that form context

The per-form inline help below the toggle is deliberately limited:

  • if Shield is unavailable, we do not show another block of body text there
  • if Shield's bot threshold is 0, we show the same warning below the toggle that also appears in the tooltip

Why The Disable Script Exists

Gravity Forms renders toggle inputs with its own field names, and a disabled control may not always be enough on its own to preserve the stored value cleanly across the UI flow.

There is a very small inline vanilla JavaScript helper that:

  • finds the visible Shield controls by name
  • disables checkbox/radio inputs
  • works for both the global and per-form settings

This is only a UI safety layer. It does not change the stored value.

Review Notes

The main code paths worth checking are:

  1. Shield settings are inserted in the right places in the Gravity Forms settings UI.
  2. Saving global settings works without the old validation error.
  3. Unsaved forms inherit the global default.
  4. Saved forms override the global default.
  5. Existing spam decisions are respected before Shield does anything.
  6. Missing or broken Shield behavior does not interrupt submissions.
  7. Unavailable Shield disables the setting without changing the stored value.
  8. Threshold 0 shows the warning in the tooltip and below the per-form toggle.

Important Callouts

  • This integration is intentionally conservative. Only a strict boolean true from Shield blocks anything.
  • Existing spam state wins. We do not overwrite earlier spam decisions.
  • Existing abort state wins. We do not override earlier draft-abort decisions.
  • Missing form state means inherit, not off.
  • First form save creates an explicit override because the UI is a binary toggle, not a tri-state inherit control.
  • When Shield is temporarily unavailable, the setting is disabled in the UI but its stored value is preserved.
  • The 'Learn More' link is a short-link that redirects to a generic page, but we'll update this closer to release with a specific page for Gravity Forms Zero Spam so that we can capture the most recent screenshots for the new help article.

Summary by CodeRabbit

  • New Features
    • Integrated Shield silentCAPTCHA into Gravity Forms Zero Spam.
    • Added global and per-form toggles, status indicators, help text, and inheritance-aware settings.
    • Uses Shield verdicts to mark submissions as spam, optionally abort draft saves, and add fallback notes when automatic spam marking isn’t available.

Wire a dedicated Shield integration into the Zero Spam add-on and route Shield verdicts through Gravity Forms spam handling, save-and-continue aborts, and fallback entry notes. Add plugin and per-form settings with normalized hidden persist fields so the extra UI state can be saved without tripping Gravity Forms validation.

Treat the plugin setting as the default and let forms inherit it until they save an explicit override. Make the admin UI state-aware by disabling controls when Shield is unavailable, surfacing threshold-zero guidance in the right context, and keeping the per-form tooltip and inline help aligned with whether the form is inheriting or overriding the global default.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 24, 2026

Walkthrough

Adds a Shield SilentCAPTCHA integration component to the GF Zero Spam add-on: initializes the component, extends plugin and per-form settings handling and normalization, and uses Shield verdicts to influence spam detection, optional draft-abort, and fallback entry-note creation.

Changes

Cohort / File(s) Summary
Main Addon Integration
includes/class-gf-zero-spam-addon.php
Added nullable Shield SilentCAPTCHA component property, instantiate and init the component in init(), and delegate Shield-specific plugin settings handling and normalization in plugin_settings_fields() and update_plugin_settings().
Shield Silent CAPTCHA Component
includes/class-gf-zero-spam-shield-silent-captcha.php
New integration class registering hooks to inject plugin & per-form settings UI, normalize/persist settings, evaluate Shield verdicts (tri-state true/false/null) in gform_entry_is_spam, optionally abort Save-and-Continue drafts on strict spam, add fallback entry notes when GFCommon API is missing, and lazy-cache Shield availability/threshold.

Sequence Diagram

sequenceDiagram
    actor User as User
    participant GF as Gravity Forms
    participant ZeroSpam as GF Zero Spam AddOn
    participant Shield as Shield SilentCAPTCHA
    participant DB as Entry DB

    User->>GF: Submit form
    GF->>ZeroSpam: gform_entry_is_spam filter
    ZeroSpam->>ZeroSpam: Check preconditions (already spam, privileged user, preview, form toggle)
    alt Precondition blocks
        ZeroSpam-->>GF: return existing spam status
    else
        ZeroSpam->>Shield: Request verdict
        Shield-->>ZeroSpam: Return verdict (true/false/null)
        alt verdict === true
            ZeroSpam->>ZeroSpam: Mark entry as spam (GFCommon if available)
            ZeroSpam-->>GF: return true
            alt Save-and-Continue draft and not editing
                ZeroSpam->>GF: abort draft creation
            end
        else
            ZeroSpam-->>GF: return false
        end
    end
    GF->>DB: Save entry
    alt fallback tracked form and GFCommon unavailable
        ZeroSpam->>DB: Add entry note marking spam verdict
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • Release 1.5.0 #49 — Modifies the same GF_Zero_Spam_AddOn initialization and settings hooks that this change extends; likely related integration work.
🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title "Add Shield silentCAPTCHA integration" directly and accurately describes the main change: introducing Shield silentCAPTCHA integration to the Zero Spam plugin. It is clear, concise, and captures the primary objective of the changeset.
Docstring Coverage ✅ Passed Docstring coverage is 86.84% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@includes/class-gf-zero-spam-shield-silent-captcha.php`:
- Around line 141-149: The current normalize_form_settings implementation always
writes back a concrete value for self::SETTING_KEY, which materializes
inherited/global defaults and prevents future global changes from propagating;
change the logic in normalize_form_settings (and the similar block around the
350-366 region) so you only set $form[self::SETTING_KEY] when the submitted or
persisted input explicitly contains the key (rgpost(self::SETTING_KEY) or
rgpost(self::PERSIST_KEY)), otherwise remove/leave the key absent to preserve
the “inherit/missing” state—use resolve_setting_value_for_save and
get_effective_form_setting_value to compute values for validation but avoid
saving that computed value back into the form when neither submitted nor
persisted values were provided.
- Around line 294-304: render_form_status_field currently only outputs the
inline help/description when is_threshold_zero() is true (and emits only JS when
is_shield_available() is false), which hides the per-form status/help row in
normal and unavailable cases; change the logic so the description HTML from
get_form_tooltip_text( $this->addon->get_current_form() ) is always rendered
(assign a $help_html using esc_html and the same <p class="description"> markup)
and then append/merge the existing render_disable_control_script() output when
is_shield_available() is false (or keep the threshold-zero branch behavior for
any extra messaging), ensuring you still call is_threshold_zero(),
is_shield_available(), render_disable_control_script(), and
get_form_tooltip_text() as reference points when restructuring the conditionals
so the help row is always visible while retaining the JS disabled controls.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 5aa6a20d-851c-4785-af06-952061522847

📥 Commits

Reviewing files that changed from the base of the PR and between d8fe2c1 and 7137df6.

📒 Files selected for processing (2)
  • includes/class-gf-zero-spam-addon.php
  • includes/class-gf-zero-spam-shield-silent-captcha.php

Comment thread includes/class-gf-zero-spam-shield-silent-captcha.php Outdated
Comment on lines +294 to +304
public function render_form_status_field( $field, $echo = true ): ?string {
$html = '';

if ( ! $this->is_shield_available() ) {
$html = $this->render_disable_control_script( [ '_gform_setting_' . self::SETTING_KEY, self::SETTING_KEY ] );
} elseif ( $this->is_threshold_zero() ) {
$html = sprintf(
'<p class="description" style="color:#996800;">%s</p>',
esc_html( $this->get_form_tooltip_text( $this->addon->get_current_form() ) )
);
}
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot Mar 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Keep the per-form status/help row visible outside the threshold-zero case.

Line 368 hides the HTML field unless the threshold is zero, so normal forms never show the inherit/override help text. When Shield is unavailable, render_form_status_field() only emits JS, so there is still no inline status/help message for that state either.

Possible fix to always render the inline help
 public function render_form_status_field( $field, $echo = true ): ?string {
-	$html = '';
-
-	if ( ! $this->is_shield_available() ) {
-		$html = $this->render_disable_control_script( [ '_gform_setting_' . self::SETTING_KEY, self::SETTING_KEY ] );
-	} elseif ( $this->is_threshold_zero() ) {
-		$html = sprintf(
-			'<p class="description" style="color:`#996800`;">%s</p>',
-			esc_html( $this->get_form_tooltip_text( $this->addon->get_current_form() ) )
-		);
-	}
+	$style = $this->is_threshold_zero() ? ' style="color:`#996800`;"' : '';
+	$html  = sprintf(
+		'<p class="description"%s>%s</p>',
+		$style,
+		esc_html( $this->get_form_tooltip_text( $this->addon->get_current_form() ) )
+	);
+
+	if ( ! $this->is_shield_available() ) {
+		$html .= $this->render_disable_control_script( [ '_gform_setting_' . self::SETTING_KEY, self::SETTING_KEY ] );
+	}

 	if ( $echo ) {
 		echo $html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Markup is escaped at source.
@@
 		[
-			'hidden'   => ! $this->is_threshold_zero(),
 			'type'     => 'html',
 			'name'     => self::STATUS_FIELD_KEY,
 			'label'    => '',
 			'callback' => [ $this, 'render_form_status_field' ],
 		],

Also applies to: 368-373

🧰 Tools
🪛 PHPMD (2.15.0)

[warning] 294-294: Avoid unused parameters such as '$field'. (undefined)

(UnusedFormalParameter)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@includes/class-gf-zero-spam-shield-silent-captcha.php` around lines 294 -
304, render_form_status_field currently only outputs the inline help/description
when is_threshold_zero() is true (and emits only JS when is_shield_available()
is false), which hides the per-form status/help row in normal and unavailable
cases; change the logic so the description HTML from get_form_tooltip_text(
$this->addon->get_current_form() ) is always rendered (assign a $help_html using
esc_html and the same <p class="description"> markup) and then append/merge the
existing render_disable_control_script() output when is_shield_available() is
false (or keep the threshold-zero branch behavior for any extra messaging),
ensuring you still call is_threshold_zero(), is_shield_available(),
render_disable_control_script(), and get_form_tooltip_text() as reference points
when restructuring the conditionals so the help row is always visible while
retaining the JS disabled controls.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is intentional - we don't pollute the UI in this section with additional HTML/helper text to keep it aligned with the other options, and because we take advantage of the tooltips that are available. This display is a special case where the info becomes unhidden so that users don't mistakenly think that because the silentCAPTCHA is switched-on that it's working. This warning alerts them to take action they would otherwise not be aware of.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@paulgoodchild, thanks for the clear explanation! That makes perfect sense — keeping the UI clean by relying on tooltips for standard help text, and reserving the visible inline paragraph exclusively as an actionable warning when the threshold-zero state would otherwise make it appear that Shield is working when it isn't. I'll note this for future reviews.


✏️ Learnings added
Learnt from: paulgoodchild
Repo: GravityKit/gravity-forms-zero-spam PR: 58
File: includes/class-gf-zero-spam-shield-silent-captcha.php:294-304
Timestamp: 2026-03-24T19:14:05.840Z
Learning: In includes/class-gf-zero-spam-shield-silent-captcha.php, the `render_form_status_field()` method intentionally only renders a visible `<p class="description">` paragraph when `is_threshold_zero()` is true. Normal per-form help text is handled via GF tooltips to keep the UI uncluttered. The visible paragraph is a special-case warning so users don't mistakenly believe silentCAPTCHA is active when the Shield threshold is zero. Do not flag this conditional rendering as missing inline help — it is by design.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


🧠 Learnings used
Learnt from: mrcasual
Repo: GravityKit/gravity-forms-zero-spam PR: 49
File: includes/class-gf-zero-spam.php:287-314
Timestamp: 2026-02-27T00:27:08.941Z
Learning: In includes/ files for the Gravity Forms Zero Spam plugin, do not maintain the legacy fallback path in check_key_field() that uses GFAPI::add_note(), since GFCommon::set_spam_filter() has been available since Gravity Forms 2.7 (Jan 2023) and the minimum requirement is 2.5+. This path is effectively unused and adds unnecessary maintenance. Ensure the plugin requires Gravity Forms 2.5+ and rely on GFCommon::set_spam_filter() for spam filtering behavior instead of the legacy NF/Note-based fallback.

Learnt from: mrcasual
Repo: GravityKit/gravity-forms-zero-spam PR: 49
File: includes/class-email-rejection-field-settings.php:62-78
Timestamp: 2026-02-26T23:39:42.394Z
Learning: In WordPress plugins, plugin_dir_url(__DIR__) resolves to the plugin root when __DIR__ is a subdirectory (e.g., includes/). To get a subdirectory URL reliably, avoid plugin_dir_url(__DIR__) in such files. Instead, use plugin_dir_url(__FILE__) and append the relative subpath, or reference assets relative to the current file. Example: in includes/class-email-rejection-field-settings.php, to link to the includes/ subdirectory, use plugin_dir_url(__FILE__) . 'includes/'; or to reference a file inside the same subdirectory, use plugin_dir_url(__FILE__) . 'path/to/asset.ext'.

Learnt from: mrcasual
Repo: GravityKit/gravity-forms-zero-spam PR: 52
File: includes/class-gf-zero-spam.php:203-204
Timestamp: 2026-03-03T17:43:25.721Z
Learning: In includes/class-gf-zero-spam.php, the 24-hour TTL fallback token is intentional: used only when REST/AJAX endpoints are unreachable to avoid false positives on restrictive hosts. Tokens are HMAC-signed, bound to the form, and include a unique nonce; since this is spam prevention rather than authentication/CSRF, replay misuse is not a concern because bots rendering pages can obtain fresh tokens. This pattern can be applied when a system must degrade gracefully with a long-lived token only as a last resort, ensuring that nonces and signing are used to mitigate replay.

@zackkatz
Copy link
Copy Markdown
Member

Thanks for the PR, Paul! We will review this soon! @paulgoodchild Please address the Coderabbit review items.

Use Gravity Forms' real form-settings save hook and prefixed field names for the Shield per-form setting. Keep inherited forms missing when an unchanged save still matches the current effective value, so later global default changes continue to propagate.

Also refresh the form status field docblock so it matches the current unavailable and threshold-warning behavior.
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
includes/class-gf-zero-spam-shield-silent-captcha.php (1)

471-486: Consider removing unused $form parameter.

The $form parameter is passed but never used in this method. If there's no planned use for per-form context rules, you could simplify the signature:

♻️ Optional cleanup
-	private function is_submission_context_supported( $form, $entry ): bool {
+	private function is_submission_context_supported( $entry ): bool {

And update the call site at line 193:

-		if ( ! $this->is_submission_context_supported( $form, $entry ) ) {
+		if ( ! $this->is_submission_context_supported( $entry ) ) {

Alternatively, if this is reserved for future per-form context rules, consider adding a brief @param docblock noting the intent.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@includes/class-gf-zero-spam-shield-silent-captcha.php` around lines 471 -
486, The method is_submission_context_supported has an unused $form
parameter—remove the parameter from the method signature and any PHPDoc for it,
and update all call sites to stop passing the $form argument (so callers invoke
is_submission_context_supported($entry) or no-arg if you also remove $entry);
alternatively if you want to keep it for future use, add a brief `@param` docblock
on is_submission_context_supported indicating it's reserved for future per-form
rules and leave calls as-is. Ensure the unique symbol
is_submission_context_supported is updated consistently across definition and
callers.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@includes/class-gf-zero-spam-shield-silent-captcha.php`:
- Around line 471-486: The method is_submission_context_supported has an unused
$form parameter—remove the parameter from the method signature and any PHPDoc
for it, and update all call sites to stop passing the $form argument (so callers
invoke is_submission_context_supported($entry) or no-arg if you also remove
$entry); alternatively if you want to keep it for future use, add a brief `@param`
docblock on is_submission_context_supported indicating it's reserved for future
per-form rules and leave calls as-is. Ensure the unique symbol
is_submission_context_supported is updated consistently across definition and
callers.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 17bfe5be-d617-4d40-b732-b55de6abccdd

📥 Commits

Reviewing files that changed from the base of the PR and between 7137df6 and 94aa30f.

📒 Files selected for processing (1)
  • includes/class-gf-zero-spam-shield-silent-captcha.php

Clean up the Shield silentCAPTCHA integration by tightening the method contracts that are safe to tighten, documenting the public filter boundary that still needs defensive handling, removing a small unused helper/signature, and reusing the existing constant for Shield-facing labels.

This keeps the behavior unchanged while making the class more precise, less noisy, and easier to review.
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
includes/class-gf-zero-spam-shield-silent-captcha.php (2)

469-484: Minor style inconsistency with isset vs rgar.

Line 483 uses isset() while the rest of the class consistently uses rgar() for array access. Consider aligning for consistency.

♻️ Optional: Consistent array access
-		return !( isset( $entry['user_agent'] ) && 'API' === $entry['user_agent'] );
+		return 'API' !== rgar( $entry, 'user_agent' );
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@includes/class-gf-zero-spam-shield-silent-captcha.php` around lines 469 -
484, In is_submission_context_supported(), replace the isset check on
$entry['user_agent'] with the project's rgar() helper for consistent array
access: use rgar( $entry, 'user_agent' ) and compare it to 'API' instead of
isset( $entry['user_agent'] ) && 'API' === $entry['user_agent']; update the
return expression accordingly so it continues to return a boolean; this keeps
the function (is_submission_context_supported) consistent with other uses of
rgar across the class and with GFFormDisplay usage.

223-237: Consider returning $do_abort for unsupported contexts.

Line 229 returns false unconditionally when not in a Save & Continue context. While this works correctly (since $do_abort is already false/falsy at this point due to the early return at line 224), returning $do_abort would be more consistent with the passthrough pattern used elsewhere in the class.

♻️ Optional: Consistent passthrough pattern
 		if ( ! rgpost( 'gform_save' ) || GFCommon::is_preview() ) {
-			return false;
+			return $do_abort;
 		}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@includes/class-gf-zero-spam-shield-silent-captcha.php` around lines 223 -
237, The function maybe_abort_submission returns false unconditionally in
unsupported contexts, which breaks the passthrough pattern; update the two early
returns that currently return false (the checks for ! rgpost('gform_save') ||
GFCommon::is_preview() and ! $this->is_shield_enabled_for_form($form)) to return
$do_abort instead so the original passthrough behavior (and any upstream abort
state) is preserved; modify the return statements inside
maybe_abort_submission() accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@includes/class-gf-zero-spam-shield-silent-captcha.php`:
- Around line 469-484: In is_submission_context_supported(), replace the isset
check on $entry['user_agent'] with the project's rgar() helper for consistent
array access: use rgar( $entry, 'user_agent' ) and compare it to 'API' instead
of isset( $entry['user_agent'] ) && 'API' === $entry['user_agent']; update the
return expression accordingly so it continues to return a boolean; this keeps
the function (is_submission_context_supported) consistent with other uses of
rgar across the class and with GFFormDisplay usage.
- Around line 223-237: The function maybe_abort_submission returns false
unconditionally in unsupported contexts, which breaks the passthrough pattern;
update the two early returns that currently return false (the checks for !
rgpost('gform_save') || GFCommon::is_preview() and !
$this->is_shield_enabled_for_form($form)) to return $do_abort instead so the
original passthrough behavior (and any upstream abort state) is preserved;
modify the return statements inside maybe_abort_submission() accordingly.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 1dc30af2-de9b-4afa-8beb-b83e34e378cd

📥 Commits

Reviewing files that changed from the base of the PR and between 94aa30f and 7ce5e43.

📒 Files selected for processing (1)
  • includes/class-gf-zero-spam-shield-silent-captcha.php

@mrcasual mrcasual self-requested a review April 2, 2026 11:09
@mrcasual mrcasual self-assigned this Apr 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants