Skip to content

Add aria-describedby attribute where missing for fields with error#2579

Open
AbdiTolesa wants to merge 76 commits into
masterfrom
issue-6068-fix_checkbox_and_radio_buttons_accessibility
Open

Add aria-describedby attribute where missing for fields with error#2579
AbdiTolesa wants to merge 76 commits into
masterfrom
issue-6068-fix_checkbox_and_radio_buttons_accessibility

Conversation

@AbdiTolesa
Copy link
Copy Markdown
Contributor

@AbdiTolesa AbdiTolesa commented Nov 10, 2025

Fix https://github.com/Strategy11/formidable-pro/issues/6078

  • Add missing aria-describedby attributes when field errors happen.
  • Make sure aria-describedby values are removed from elements when errors are cleared, during Ajax submission
  1. Create a form and add Checkbox, Radio and Dropdown fields to it.
  2. Set constraints like Required in the fields options.
  3. Preview the forms and try submitting the form without filling the fields so that errors are triggered.
  4. Confirm that aria-describedby attribute is added to the elements to link them to the error message element programatically.
  5. Repeat the test under different form settings, like JS validation, Ajax submission etc.

Summary by CodeRabbit

  • Enhancements
    • Improved form field accessibility with enhanced ARIA support for screen readers on input fields and error messages.
    • Better error message handling with refined alert role management for users relying on assistive technologies.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Nov 10, 2025

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The PR improves form field accessibility by exposing ARIA description handling as a public API and propagating field arguments through field templates to JavaScript, while simultaneously establishing comprehensive development standards documentation for enterprise, Formidable Forms, WordPress, and VIP codebases.

Changes

Form Field ARIA Accessibility Enhancements

Layer / File(s) Summary
ARIA method visibility and public API
classes/models/fields/FrmFieldType.php
add_aria_description() is promoted from protected to public with updated docblock documentation, establishing a reusable contract for ARIA attribute management.
Field template argument propagation
classes/views/frm-fields/front-end/checkbox-field.php, dropdown-field.php, radio-field.php
Templates are updated with @var PHPDoc annotations and conditionally assign $args into the $field array before firing frm_field_input_html, enabling downstream hooks to read field arguments.
Field controller ARIA integration
classes/controllers/FrmFieldsController.php
The input_html() method now builds HTML into a dedicated $html variable, instantiates the field type object, and invokes the public add_aria_description() method when $field['args'] is present.
Error alert role handling
classes/models/FrmFieldFormHtml.php
replace_error_shortcode() explicitly manages three error states: early exit on no error, conditional alert role injection when enabled and missing, and role removal when disabled but present.

Development Standards & Tooling

Layer / File(s) Summary
Editor configuration and linting setup
.devin/.editorconfig, .devin/.markdownlint.json
Establishes tab-based indentation, markdown heading style (atx), custom rule indentation (4 spaces), and disables line-length and hard-tab enforcement.
Enterprise coding standards and practices
.devin/rules/enterprise/*
Documents phased code-change principles (analyze/understand/locate/research, select, implement, verify with compatibility/edge-case testing), conventional commit formatting (types, scopes, 50/72 limits, examples, AI generation), and ecosystem-wide style/documentation rules.
Formidable Forms coding standards
.devin/rules/formidable/frm-*.md
Defines Formidable-specific standards for CSS (styling, stylelint rules), JavaScript (no jQuery, functional patterns, frmDom/DOM/async/state conventions, ESLint), PHP (versions 7.0+, WordPress 6.3+, PHPCS sniffs), React (hooks, @wordpress/* packages, memoization, data layer), security (input/nonce/serialization/DOM sanitization/authorization), and testing (scenarios, AAA, test context, assertion best practices).
WordPress and VIP standards
.devin/rules/wordpress*/*, .devin/rules/wordpress-vip/*
Documents WordPress accessibility (WCAG 2.2 AA), block editor standards, HTML/JavaScript/PHP coding conventions, and VIP-specific guidance on block editor features, performance optimization (queries, caching, hooks, cron, batch processing, asset loading), and OWASP-aligned security patterns.
Development skills and tooling
.devin/skills/eslint-rules/SKILL.md, .devin/skills/fix-bug/*
Provides skill documentation for custom ESLint rule creation and structured bug-fix workflows, including PR/report/solution templates, checklists, and manual invocation guidance.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested reviewers

  • Crabcyborg
  • garretlaxton

Poem

🐰 With ARIA descriptions now in sight,
Form fields dance with accessibility delight,
Standards documented from top to toe,
A rabbit's code review steals the show! 🌟

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 3.51% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the main change: adding aria-describedby attributes to form fields with validation errors for accessibility.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch issue-6068-fix_checkbox_and_radio_buttons_accessibility

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
Contributor

@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: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ca9cb12 and 603d9b1.

📒 Files selected for processing (2)
  • classes/views/frm-fields/front-end/dropdown-field.php (1 hunks)
  • classes/views/frm-fields/front-end/radio-field.php (1 hunks)
🧰 Additional context used
🪛 GitHub Check: PHPStan
classes/views/frm-fields/front-end/radio-field.php

[failure] 57-57:
Implicit array creation is not allowed - variable $field might not exist.

🔇 Additional comments (1)
classes/views/frm-fields/front-end/radio-field.php (1)

57-58: <!-- [scratchpad_start]
[task review_file_1/1 verify_args_availability 3/3 COMPLETE]
Final verification complete - $args is in scope

[observations]

  • Found FrmFieldType::include_on_front_form() at lines 1071-1098
  • Template file included directly via: include $include_file; (line 1093)
  • Variables available in template scope:
    • $args (passed as parameter at line 1071, not removed)
    • $field (assigned at line 1085 from $this->field)
    • $html_id (assigned at line 1086)
    • $field_name (assigned at line 1087)
    • $read_only (assigned at line 1088)
  • NO extract() call - variables made available via direct assignment
  • Before include, only $args['form'] is unset (line 1090)

[analysis]

  • $args parameter is passed through to include_on_front_form()
  • All variables needed by template are in scope before include
  • Radio-field.php line 57: $field['args'] = $args; is VALID
  • $args is definitely in scope when template executes
  • No undefined variable error can occur

[conclusion]

  • Review comment concern is INVALID
  • The code is CORRECT
  • $args is proven to be in scope
  • No changes needed
  • All similar files (checkbox-field.php, dropdown-field.php) follow same pattern

[done]
Verification complete: NO ISSUES FOUND

No issues found. The $args variable is properly in scope.

The template file is included at line 1093 of FrmFieldType::include_on_front_form() with $args passed as a parameter and available in the local scope. Additional variables like $field, $html_id, and $field_name are assigned before the include statement, making them available to the template. The assignment $field['args'] = $args; at lines 57-58 in radio-field.php is valid and safe.

Comment thread classes/views/frm-fields/front-end/dropdown-field.php
Copy link
Copy Markdown
Contributor

@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: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 603d9b1 and 60c34ef.

📒 Files selected for processing (1)
  • js/formidable.js (1 hunks)

Comment thread js/formidable.js Outdated
Copy link
Copy Markdown
Contributor

@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: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 60c34ef and 39cf3ed.

📒 Files selected for processing (3)
  • classes/controllers/FrmFieldsController.php (1 hunks)
  • classes/models/fields/FrmFieldType.php (1 hunks)
  • classes/views/frm-fields/front-end/checkbox-field.php (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • classes/views/frm-fields/front-end/checkbox-field.php
  • classes/models/fields/FrmFieldType.php
🧰 Additional context used
🧬 Code graph analysis (1)
classes/controllers/FrmFieldsController.php (2)
classes/factories/FrmFieldFactory.php (2)
  • FrmFieldFactory (9-141)
  • get_field_object (58-64)
classes/models/fields/FrmFieldType.php (1)
  • add_aria_description (1362-1410)
🔇 Additional comments (1)
classes/controllers/FrmFieldsController.php (1)

527-527: Refactoring approach looks good.

The introduction of the $html variable to store the constructed HTML before output is a clean approach that allows the ARIA description to be conditionally added before echoing or returning. This separation of HTML construction and output handling makes the code more maintainable.

Also applies to: 534-538

@lauramekaj1
Copy link
Copy Markdown
Contributor

Hi @AbdiTolesa, there are some error warnings showing in this branch. Please see the attached screenshot:
image

@AbdiTolesa
Copy link
Copy Markdown
Contributor Author

Hi @AbdiTolesa, there are some error warnings showing in this branch. Please see the attached screenshot:

Hi @lauramekaj1 Just fixed those.

Copy link
Copy Markdown
Contributor

@lauramekaj1 lauramekaj1 left a comment

Choose a reason for hiding this comment

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

@AbdiTolesa I tested it and it's working as expected. Thank you!

Copy link
Copy Markdown
Contributor

@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: 1

🧹 Nitpick comments (1)
classes/views/frm-fields/front-end/checkbox-field.php (1)

76-79: Passing $args via $field['args'] into the hook is consistent and safe

Conditionally attaching $args onto $field before frm_field_input_html gives hook callbacks the extra context they need (e.g., for ARIA handling) without changing the hook signature or breaking existing consumers. The isset( $args ) guard avoids notices when $args is not provided, and reusing the mutated $field later in this template remains compatible with current usage.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2058760 and b6faf96.

📒 Files selected for processing (5)
  • classes/controllers/FrmFieldsController.php (1 hunks)
  • classes/models/FrmFieldFormHtml.php (1 hunks)
  • classes/views/frm-fields/front-end/checkbox-field.php (2 hunks)
  • classes/views/frm-fields/front-end/dropdown-field.php (1 hunks)
  • classes/views/frm-fields/front-end/radio-field.php (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • classes/views/frm-fields/front-end/radio-field.php
  • classes/views/frm-fields/front-end/dropdown-field.php
  • classes/controllers/FrmFieldsController.php
🧰 Additional context used
🧬 Code graph analysis (1)
classes/models/FrmFieldFormHtml.php (1)
classes/helpers/FrmAppHelper.php (2)
  • FrmAppHelper (6-4666)
  • should_include_alert_role_on_field_errors (3684-3686)
🔇 Additional comments (1)
classes/views/frm-fields/front-end/checkbox-field.php (1)

11-16: Docblock variable annotations are clear and accurate

The added @var annotations correctly document the template variables and their types, improving readability and IDE support without affecting runtime behavior.

Comment thread classes/models/FrmFieldFormHtml.php
@AbdiTolesa AbdiTolesa requested a review from truongwp November 20, 2025 11:39
Comment thread classes/controllers/FrmFieldsController.php Outdated
Comment thread classes/models/FrmFieldFormHtml.php
@AbdiTolesa AbdiTolesa requested a review from truongwp November 21, 2025 10:58
Copy link
Copy Markdown
Contributor

@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: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ec5d850 and 4482d15.

📒 Files selected for processing (2)
  • classes/controllers/FrmFieldsController.php (1 hunks)
  • classes/models/FrmFieldFormHtml.php (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • classes/controllers/FrmFieldsController.php
🧰 Additional context used
🧬 Code graph analysis (1)
classes/models/FrmFieldFormHtml.php (1)
classes/helpers/FrmAppHelper.php (2)
  • FrmAppHelper (6-4666)
  • should_include_alert_role_on_field_errors (3684-3686)
🪛 GitHub Check: PHPStan
classes/models/FrmFieldFormHtml.php

[failure] 236-236:
Variable $error in empty() always exists and is always falsy.

🔇 Additional comments (1)
classes/models/FrmFieldFormHtml.php (1)

239-249: LGTM! Role injection/removal logic is correct.

The logic correctly handles role="alert" injection and removal:

  • Line 240: $has_alert_role correctly indicates presence (fixed from previous inverted logic)
  • Line 241: Injects role when missing AND setting allows
  • Line 247: Removes role when present AND setting disallows

The early return at line 235 ensures this block only executes when an error exists, addressing truongwp's concern from the previous review.

Comment thread classes/models/FrmFieldFormHtml.php Outdated
Copy link
Copy Markdown
Contributor

@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: 0

🧹 Nitpick comments (1)
classes/models/FrmFieldFormHtml.php (1)

235-237: Consider separating the function call from the return statement.

The code returns the result of FrmShortcodeHelper::remove_inline_conditions(), but this function modifies $this->html by reference and doesn't return a meaningful value (as seen on line 251 where it's called without capturing the return). While functionally correct, explicitly separating the call from the return improves clarity.

Apply this diff for clearer intent:

 if ( empty( $error ) ) {
-	return FrmShortcodeHelper::remove_inline_conditions( false, 'error', $error, $this->html );
+	FrmShortcodeHelper::remove_inline_conditions( false, 'error', $error, $this->html );
+	return;
 }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4482d15 and 2b43dd8.

📒 Files selected for processing (1)
  • classes/models/FrmFieldFormHtml.php (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
classes/models/FrmFieldFormHtml.php (1)
classes/helpers/FrmAppHelper.php (2)
  • FrmAppHelper (6-4666)
  • should_include_alert_role_on_field_errors (3684-3686)
🔇 Additional comments (1)
classes/models/FrmFieldFormHtml.php (1)

239-251: LGTM! Alert role logic is now correct.

The inverted logic bug has been successfully resolved. The variable $has_alert_role now correctly reflects whether role="alert" is present in the HTML (false !== strpos(...) evaluates to true when found). The conditional branches properly inject the role when missing and enabled, or remove it when present but disabled.

@AbdiTolesa AbdiTolesa removed the request for review from truongwp November 27, 2025 13:32
@deepsource-io
Copy link
Copy Markdown

deepsource-io Bot commented Jun 4, 2026

DeepSource Code Review

We reviewed changes in 4fd6ff1...0f42619 on this pull request. Below is the summary for the review, and you can see the individual issues we found as inline review comments.

See full review on DeepSource ↗

Code Review Summary

Analyzer Status Updated (UTC) Details
PHP Jun 4, 2026 7:17p.m. Review ↗
JavaScript Jun 4, 2026 7:17p.m. Review ↗

Important

AI Review is run only on demand for your team. We're only showing results of static analysis review right now. To trigger AI Review, comment @deepsourcebot review on this thread.

self::add_pattern_attribute( $field, $add_html );
self::add_currency_field_attributes( $field, $add_html );

$add_html = apply_filters( 'frm_field_extra_html', $add_html, $field );
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Function apply_filters invoked with 3 parameters, 2 required


The function call is not valid, which will result in a fatal runtime error.

@@ -24,7 +24,12 @@
if ( $read_only ) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Variable $read_only might not be defined


A variable has been used but not defined, which may result in warnings during program execution. This can also cause bugs since the intended usage scope of the variable is not known.

$field['args'] = $args;
}
?>
<select name="<?php echo esc_attr( $field_name ); ?>" id="<?php echo esc_attr( $html_id ); ?>" <?php do_action( 'frm_field_input_html', $field ); ?>>
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Variable $field_name might not be defined


A variable has been used but not defined, which may result in warnings during program execution. This can also cause bugs since the intended usage scope of the variable is not known.

$field['args'] = $args;
}
?>
<select name="<?php echo esc_attr( $field_name ); ?>" id="<?php echo esc_attr( $html_id ); ?>" <?php do_action( 'frm_field_input_html', $field ); ?>>
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Variable $html_id might not be defined


A variable has been used but not defined, which may result in warnings during program execution. This can also cause bugs since the intended usage scope of the variable is not known.

@deepsource-io
Copy link
Copy Markdown

deepsource-io Bot commented Jun 4, 2026

DeepSource Code Review

We reviewed changes in b7cd07c...a76eb3f on this pull request. Below is the summary for the review, and you can see the individual issues we found as inline review comments.

See full review on DeepSource ↗

Important

Some issues found as part of this review are outside of the diff in this pull request and aren't shown in the inline review comments due to GitHub's API limitations. You can see those issues on the DeepSource dashboard.

PR Report Card

Overall Grade   Security  

Reliability  

Complexity  

Hygiene  

Code Review Summary

Analyzer Status Updated (UTC) Details
PHP Jun 5, 2026 5:11p.m. Review ↗
JavaScript Jun 5, 2026 5:11p.m. Review ↗

Important

AI Review is run only on demand for your team. We're only showing results of static analysis review right now. To trigger AI Review, comment @deepsourcebot review on this thread.

Copy link
Copy Markdown
Contributor

@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: 9

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.devin/rules/formidable/frm-php.md:
- Around line 33-34: Update the PHP version mapping for the "Return type
declarations" entry in .devin/rules/formidable/frm-php.md: change the listed
"NOT Allowed" version from 7.1 to 7.0 for the table row labeled "Return type
declarations" so it correctly reflects that return type declarations were
introduced in PHP 7.0.

In @.devin/rules/formidable/frm-react.md:
- Around line 429-431: The thunk example assigns items from response.json()
without awaiting, causing a Promise to be dispatched; update the parsing to
await the JSON: when using apiFetch and the local variable response (from
apiFetch), change the items assignment to await response.json() so dispatch({
type: 'FETCH_SUCCESS', items }) receives the resolved data rather than a pending
Promise (references: apiFetch, response, response.json(), items, dispatch,
'FETCH_SUCCESS').

In @.devin/rules/wordpress-vip/wpvip-performance.md:
- Around line 284-286: Guard access to the global $post before reading
$post->post_content in the shortcode example: ensure the global $post is
declared and non-null (and ideally is_object or instance of WP_Post) or fallback
to get_post() before calling has_shortcode on post_content; only call
has_shortcode( … , 'my_shortcode' ) and wp_enqueue_script('my-shortcode-script')
when you have a valid post object and its post_content is available to avoid
notices in archives/hooks/CLI (update the snippet around global $post,
has_shortcode, and wp_enqueue_script to perform this check).

In @.devin/rules/wordpress/html.md:
- Line 191: The file contains duplicate markdown heading text "### Lowercase"
which triggers MD024; rename one of the headings (for example change the second
"### Lowercase" to "### Lowercase Tag Names" or a similarly specific title) and
update any internal references or anchor links that rely on that heading so they
continue to point to the correct section; ensure the new heading is unique and
descriptive.

In @.devin/skills/eslint-rules/SKILL.md:
- Around line 23-113: The SKILL.md is missing three rules that are exported from
eslint-rules/index.js; update the plugin tree and the "Existing Rules" section
to include prefer-truthy-dom-query, prefer-optional-chaining, and
no-jquery-variable-methods (use these exact identifiers), adding a subsection
for each with their fixability, severity, brief description and
examples/patterns they catch, and make sure the top file list under
eslint-rules/ includes their filenames (as in index.js) so the documentation
matches the actual registry.

In @.devin/skills/fix-bug/checklist.md:
- Around line 7-13: The checklist entries in checklist.md reference the old
rules namespace (strings like ".windsurf/rules/formidable/frm-php.md",
".windsurf/rules/wordpress/php.md", etc.) instead of the active `.devin` rule
catalog; update those entries to point to the `.devin` equivalents (e.g.,
replace ".windsurf/rules/..." with ".devin/rules/...") so the checklist paths
match the skill's active rules namespace and the new catalog.

In @.devin/skills/fix-bug/SKILL.md:
- Around line 23-34: The table in .devin/skills/fix-bug/SKILL.md references
inconsistent rule paths and a wrong test filename; update the entries that list
`*.php`, `*.js`, `*.css`, `*.html`, block editor, UI/forms, and Tests so they
point to the current rule location `.devin/rules/...` (not
`.windsurf/rules/...`) and replace `formidable/testing.md` with the correct
`frm-testing.md` filename, ensuring each referenced rule file name (e.g.,
`formidable/frm-php.md`, `formidable/frm-javascript.md`,
`formidable/frm-css.md`, `wordpress/html.md`, `wordpress/accessibility.md`)
matches the real files under `.devin/rules/`.

In `@classes/controllers/FrmFieldsController.php`:
- Line 1174: Add a defensive existence check before accessing $field['id'] in
the call to FrmFieldFactory::get_field_object: verify isset($field['id']) (or
array_key_exists) and handle the missing-key case (e.g., skip processing that
$field, log an error/warning, or set $field_obj to null) so that
FrmFieldFactory::get_field_object is only called with a valid id and $field_obj
is not created from a malformed $field.
- Around line 1150-1151: The code uses json_encode($product_field) directly when
building $add_html['data-frmproduct'], but json_encode can return false on
failure; update the FrmField::get_option handling so you encode into a variable,
check json_last_error() (or that the result !== false), and only add the
data-frmproduct attribute with esc_attr($encoded) when encoding succeeded
(otherwise either omit the attribute or set it to a safe fallback like '{}');
reference the existing $product_field, the json_encode call, esc_attr usage and
$add_html['data-frmproduct'] when making the change.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: d9af0d76-1b0b-4fcf-8f99-89044f853176

📥 Commits

Reviewing files that changed from the base of the PR and between 966aabe and 0f42619.

📒 Files selected for processing (31)
  • .devin/.editorconfig
  • .devin/.markdownlint.json
  • .devin/rules/enterprise/code-change-principles.md
  • .devin/rules/enterprise/conventional-commits.md
  • .devin/rules/enterprise/principles.md
  • .devin/rules/formidable/frm-css.md
  • .devin/rules/formidable/frm-javascript.md
  • .devin/rules/formidable/frm-php.md
  • .devin/rules/formidable/frm-react.md
  • .devin/rules/formidable/frm-security.md
  • .devin/rules/formidable/frm-testing.md
  • .devin/rules/wordpress-vip/wpvip-block-editor.md
  • .devin/rules/wordpress-vip/wpvip-performance.md
  • .devin/rules/wordpress-vip/wpvip-security.md
  • .devin/rules/wordpress/accessibility.md
  • .devin/rules/wordpress/block-editor.md
  • .devin/rules/wordpress/html.md
  • .devin/rules/wordpress/javascript.md
  • .devin/rules/wordpress/php.md
  • .devin/skills/eslint-rules/SKILL.md
  • .devin/skills/fix-bug/SKILL.md
  • .devin/skills/fix-bug/checklist.md
  • .devin/skills/fix-bug/pr-template.md
  • .devin/skills/fix-bug/report-template.md
  • .devin/skills/fix-bug/solution-template.md
  • classes/controllers/FrmFieldsController.php
  • classes/models/FrmFieldFormHtml.php
  • classes/models/fields/FrmFieldType.php
  • classes/views/frm-fields/front-end/checkbox-field.php
  • classes/views/frm-fields/front-end/dropdown-field.php
  • classes/views/frm-fields/front-end/radio-field.php
💤 Files with no reviewable changes (5)
  • classes/views/frm-fields/front-end/radio-field.php
  • classes/views/frm-fields/front-end/dropdown-field.php
  • classes/views/frm-fields/front-end/checkbox-field.php
  • classes/models/FrmFieldFormHtml.php
  • classes/models/fields/FrmFieldType.php
✅ Files skipped from review due to trivial changes (9)
  • .devin/skills/fix-bug/report-template.md
  • .devin/.editorconfig
  • .devin/.markdownlint.json
  • .devin/skills/fix-bug/solution-template.md
  • .devin/rules/formidable/frm-css.md
  • .devin/rules/wordpress/accessibility.md
  • .devin/rules/wordpress-vip/wpvip-block-editor.md
  • .devin/rules/formidable/frm-javascript.md
  • .devin/rules/formidable/frm-testing.md

Copy link
Copy Markdown
Contributor

@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.

Caution

Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 9

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.devin/rules/formidable/frm-php.md:
- Around line 33-34: Update the PHP version mapping for the "Return type
declarations" entry in .devin/rules/formidable/frm-php.md: change the listed
"NOT Allowed" version from 7.1 to 7.0 for the table row labeled "Return type
declarations" so it correctly reflects that return type declarations were
introduced in PHP 7.0.

In @.devin/rules/formidable/frm-react.md:
- Around line 429-431: The thunk example assigns items from response.json()
without awaiting, causing a Promise to be dispatched; update the parsing to
await the JSON: when using apiFetch and the local variable response (from
apiFetch), change the items assignment to await response.json() so dispatch({
type: 'FETCH_SUCCESS', items }) receives the resolved data rather than a pending
Promise (references: apiFetch, response, response.json(), items, dispatch,
'FETCH_SUCCESS').

In @.devin/rules/wordpress-vip/wpvip-performance.md:
- Around line 284-286: Guard access to the global $post before reading
$post->post_content in the shortcode example: ensure the global $post is
declared and non-null (and ideally is_object or instance of WP_Post) or fallback
to get_post() before calling has_shortcode on post_content; only call
has_shortcode( … , 'my_shortcode' ) and wp_enqueue_script('my-shortcode-script')
when you have a valid post object and its post_content is available to avoid
notices in archives/hooks/CLI (update the snippet around global $post,
has_shortcode, and wp_enqueue_script to perform this check).

In @.devin/rules/wordpress/html.md:
- Line 191: The file contains duplicate markdown heading text "### Lowercase"
which triggers MD024; rename one of the headings (for example change the second
"### Lowercase" to "### Lowercase Tag Names" or a similarly specific title) and
update any internal references or anchor links that rely on that heading so they
continue to point to the correct section; ensure the new heading is unique and
descriptive.

In @.devin/skills/eslint-rules/SKILL.md:
- Around line 23-113: The SKILL.md is missing three rules that are exported from
eslint-rules/index.js; update the plugin tree and the "Existing Rules" section
to include prefer-truthy-dom-query, prefer-optional-chaining, and
no-jquery-variable-methods (use these exact identifiers), adding a subsection
for each with their fixability, severity, brief description and
examples/patterns they catch, and make sure the top file list under
eslint-rules/ includes their filenames (as in index.js) so the documentation
matches the actual registry.

In @.devin/skills/fix-bug/checklist.md:
- Around line 7-13: The checklist entries in checklist.md reference the old
rules namespace (strings like ".windsurf/rules/formidable/frm-php.md",
".windsurf/rules/wordpress/php.md", etc.) instead of the active `.devin` rule
catalog; update those entries to point to the `.devin` equivalents (e.g.,
replace ".windsurf/rules/..." with ".devin/rules/...") so the checklist paths
match the skill's active rules namespace and the new catalog.

In @.devin/skills/fix-bug/SKILL.md:
- Around line 23-34: The table in .devin/skills/fix-bug/SKILL.md references
inconsistent rule paths and a wrong test filename; update the entries that list
`*.php`, `*.js`, `*.css`, `*.html`, block editor, UI/forms, and Tests so they
point to the current rule location `.devin/rules/...` (not
`.windsurf/rules/...`) and replace `formidable/testing.md` with the correct
`frm-testing.md` filename, ensuring each referenced rule file name (e.g.,
`formidable/frm-php.md`, `formidable/frm-javascript.md`,
`formidable/frm-css.md`, `wordpress/html.md`, `wordpress/accessibility.md`)
matches the real files under `.devin/rules/`.

In `@classes/controllers/FrmFieldsController.php`:
- Line 1174: Add a defensive existence check before accessing $field['id'] in
the call to FrmFieldFactory::get_field_object: verify isset($field['id']) (or
array_key_exists) and handle the missing-key case (e.g., skip processing that
$field, log an error/warning, or set $field_obj to null) so that
FrmFieldFactory::get_field_object is only called with a valid id and $field_obj
is not created from a malformed $field.
- Around line 1150-1151: The code uses json_encode($product_field) directly when
building $add_html['data-frmproduct'], but json_encode can return false on
failure; update the FrmField::get_option handling so you encode into a variable,
check json_last_error() (or that the result !== false), and only add the
data-frmproduct attribute with esc_attr($encoded) when encoding succeeded
(otherwise either omit the attribute or set it to a safe fallback like '{}');
reference the existing $product_field, the json_encode call, esc_attr usage and
$add_html['data-frmproduct'] when making the change.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: d9af0d76-1b0b-4fcf-8f99-89044f853176

📥 Commits

Reviewing files that changed from the base of the PR and between 966aabe and 0f42619.

📒 Files selected for processing (31)
  • .devin/.editorconfig
  • .devin/.markdownlint.json
  • .devin/rules/enterprise/code-change-principles.md
  • .devin/rules/enterprise/conventional-commits.md
  • .devin/rules/enterprise/principles.md
  • .devin/rules/formidable/frm-css.md
  • .devin/rules/formidable/frm-javascript.md
  • .devin/rules/formidable/frm-php.md
  • .devin/rules/formidable/frm-react.md
  • .devin/rules/formidable/frm-security.md
  • .devin/rules/formidable/frm-testing.md
  • .devin/rules/wordpress-vip/wpvip-block-editor.md
  • .devin/rules/wordpress-vip/wpvip-performance.md
  • .devin/rules/wordpress-vip/wpvip-security.md
  • .devin/rules/wordpress/accessibility.md
  • .devin/rules/wordpress/block-editor.md
  • .devin/rules/wordpress/html.md
  • .devin/rules/wordpress/javascript.md
  • .devin/rules/wordpress/php.md
  • .devin/skills/eslint-rules/SKILL.md
  • .devin/skills/fix-bug/SKILL.md
  • .devin/skills/fix-bug/checklist.md
  • .devin/skills/fix-bug/pr-template.md
  • .devin/skills/fix-bug/report-template.md
  • .devin/skills/fix-bug/solution-template.md
  • classes/controllers/FrmFieldsController.php
  • classes/models/FrmFieldFormHtml.php
  • classes/models/fields/FrmFieldType.php
  • classes/views/frm-fields/front-end/checkbox-field.php
  • classes/views/frm-fields/front-end/dropdown-field.php
  • classes/views/frm-fields/front-end/radio-field.php
💤 Files with no reviewable changes (5)
  • classes/views/frm-fields/front-end/radio-field.php
  • classes/views/frm-fields/front-end/dropdown-field.php
  • classes/views/frm-fields/front-end/checkbox-field.php
  • classes/models/FrmFieldFormHtml.php
  • classes/models/fields/FrmFieldType.php
✅ Files skipped from review due to trivial changes (9)
  • .devin/skills/fix-bug/report-template.md
  • .devin/.editorconfig
  • .devin/.markdownlint.json
  • .devin/skills/fix-bug/solution-template.md
  • .devin/rules/formidable/frm-css.md
  • .devin/rules/wordpress/accessibility.md
  • .devin/rules/wordpress-vip/wpvip-block-editor.md
  • .devin/rules/formidable/frm-javascript.md
  • .devin/rules/formidable/frm-testing.md
🛑 Comments failed to post (9)
.devin/rules/formidable/frm-php.md (1)

33-34: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

In official PHP documentation, which PHP version introduced function return type declarations?

💡 Result:

In the official PHP documentation, function return type declarations were introduced in PHP 7.0 [1][2][3]. This feature allows developers to specify the expected return type of a function, method, or closure by placing a colon and the type after the parameter list [2][3]. Subsequent PHP versions expanded this feature, such as the addition of nullable types and the void return type in PHP 7.1 [4][5].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

FILE=".devin/rules/formidable/frm-php.md"
nl -ba "$FILE" | sed -n '20,45p'

Repository: Strategy11/formidable-forms

Length of output: 114


🏁 Script executed:

#!/bin/bash
set -euo pipefail

FILE=".devin/rules/formidable/frm-php.md"
cat -n "$FILE" | sed -n '25,45p'

Repository: Strategy11/formidable-forms

Length of output: 1539


Fix PHP version mapping for “Return type declarations”

.devin/rules/formidable/frm-php.md lists “Return type declarations” as 7.1, but PHP return type declarations were introduced in PHP 7.0—this mislabels the “NOT Allowed” version and can lead to incorrect review outcomes.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.devin/rules/formidable/frm-php.md around lines 33 - 34, Update the PHP
version mapping for the "Return type declarations" entry in
.devin/rules/formidable/frm-php.md: change the listed "NOT Allowed" version from
7.1 to 7.0 for the table row labeled "Return type declarations" so it correctly
reflects that return type declarations were introduced in PHP 7.0.
.devin/rules/formidable/frm-react.md (1)

429-431: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

Does the Fetch API Response.json() method return a Promise, and should it be awaited in async functions?

💡 Result:

Yes, the Fetch API Response.json method returns a Promise [1][2]. This Promise resolves with the result of parsing the response body text as a JavaScript object [1][3]. Because the method is asynchronous and returns a Promise, it should be awaited when used within an async function to ensure you access the parsed data rather than the pending promise itself [4][5]. The reason this method must be awaited is that the fetch call resolves as soon as the response headers are received, which may occur before the actual body content has been fully downloaded [4][6]. Therefore, calling json initiates a separate asynchronous process to read and parse the stream of body data [1][4].

Citations:


Fix async parsing in thunk example (await response.json()).

Response.json() returns a Promise, so this should be awaited to avoid dispatching a pending promise instead of the parsed items.

Proposed fix
-			const items = response.json();
+			const items = await response.json();
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

				const response = await apiFetch( { path: '/api/items' } );
				const items = await response.json();
				dispatch( { type: 'FETCH_SUCCESS', items } );
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.devin/rules/formidable/frm-react.md around lines 429 - 431, The thunk
example assigns items from response.json() without awaiting, causing a Promise
to be dispatched; update the parsing to await the JSON: when using apiFetch and
the local variable response (from apiFetch), change the items assignment to
await response.json() so dispatch({ type: 'FETCH_SUCCESS', items }) receives the
resolved data rather than a pending Promise (references: apiFetch, response,
response.json(), items, dispatch, 'FETCH_SUCCESS').
.devin/rules/wordpress-vip/wpvip-performance.md (1)

284-286: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Guard $post before accessing post_content in the shortcode example.

This snippet can emit notices when global $post is unavailable (archives, some hooks, CLI). Please show a guarded pattern so the rule doesn’t teach a brittle example.

Suggested doc snippet update
 global $post;
-if ( has_shortcode( $post->post_content, 'my_shortcode' ) ) {
+if ( $post instanceof WP_Post && has_shortcode( $post->post_content, 'my_shortcode' ) ) {
 	wp_enqueue_script( 'my-shortcode-script' );
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.devin/rules/wordpress-vip/wpvip-performance.md around lines 284 - 286,
Guard access to the global $post before reading $post->post_content in the
shortcode example: ensure the global $post is declared and non-null (and ideally
is_object or instance of WP_Post) or fallback to get_post() before calling
has_shortcode on post_content; only call has_shortcode( … , 'my_shortcode' ) and
wp_enqueue_script('my-shortcode-script') when you have a valid post object and
its post_content is available to avoid notices in archives/hooks/CLI (update the
snippet around global $post, has_shortcode, and wp_enqueue_script to perform
this check).
.devin/rules/wordpress/html.md (1)

191-191: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Resolve duplicate markdown heading text (MD024).

This file has repeated ### Lowercase headings, which can trip markdown lint and hurt anchor clarity. Consider renaming one (e.g., ### Lowercase Tag Names).

🧰 Tools
🪛 markdownlint-cli2 (0.22.1)

[warning] 191-191: Multiple headings with the same content

(MD024, no-duplicate-heading)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.devin/rules/wordpress/html.md at line 191, The file contains duplicate
markdown heading text "### Lowercase" which triggers MD024; rename one of the
headings (for example change the second "### Lowercase" to "### Lowercase Tag
Names" or a similarly specific title) and update any internal references or
anchor links that rely on that heading so they continue to point to the correct
section; ensure the new heading is unique and descriptive.
.devin/skills/eslint-rules/SKILL.md (1)

23-113: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Rule inventory is incomplete vs actual plugin registry.

The architecture tree and “Existing Rules” section omit currently exported rules (prefer-truthy-dom-query, prefer-optional-chaining, no-jquery-variable-methods), so the skill doc is out of sync with eslint-rules/index.js.

Suggested doc sync
 eslint-rules/
 ├── index.js          # Plugin entry point, exports all rules
 └── rules/            # Individual rule files
 ...
     ├── no-repeated-selector.js
     └── prefer-document-fragment.js
+    ├── prefer-truthy-dom-query.js
+    ├── prefer-optional-chaining.js
+    └── no-jquery-variable-methods.js

Also add matching subsections under Existing Rules for the same three rules.

🧰 Tools
🪛 LanguageTool

[style] ~85-~85: Using many exclamation marks might seem excessive (in this case: 7 exclamation marks for a text that’s 4104 characters long)
Context: ...d' == typeof x(yoda) - Both===/!==and==/!=` variants ### formidable/no-optional-...

(EN_EXCESSIVE_EXCLAMATION)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.devin/skills/eslint-rules/SKILL.md around lines 23 - 113, The SKILL.md is
missing three rules that are exported from eslint-rules/index.js; update the
plugin tree and the "Existing Rules" section to include prefer-truthy-dom-query,
prefer-optional-chaining, and no-jquery-variable-methods (use these exact
identifiers), adding a subsection for each with their fixability, severity,
brief description and examples/patterns they catch, and make sure the top file
list under eslint-rules/ includes their filenames (as in index.js) so the
documentation matches the actual registry.
.devin/skills/fix-bug/checklist.md (1)

7-13: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Checklist paths should match the active rules namespace.

These checklist entries still point to .windsurf/rules/..., which is inconsistent with the .devin rule catalog added in this stack and with this skill’s location.

🧰 Tools
🪛 LanguageTool

[uncategorized] ~8-~8: The official name of this content management system is spelled with a capital “P”.
Context: ...e/frm-php.md(PHP files) - [ ] Follows.windsurf/rules/wordpress/php.md(PHP files) - [ ] Follows.win...

(WORDPRESS)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.devin/skills/fix-bug/checklist.md around lines 7 - 13, The checklist
entries in checklist.md reference the old rules namespace (strings like
".windsurf/rules/formidable/frm-php.md", ".windsurf/rules/wordpress/php.md",
etc.) instead of the active `.devin` rule catalog; update those entries to point
to the `.devin` equivalents (e.g., replace ".windsurf/rules/..." with
".devin/rules/...") so the checklist paths match the skill's active rules
namespace and the new catalog.
.devin/skills/fix-bug/SKILL.md (1)

23-34: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Coding-standards links use inconsistent path/filename conventions.

This table mixes .windsurf/rules/... references from the old location and a non-matching testing filename (formidable/testing.md). In this PR’s rule set, the docs are under .devin/rules/... and testing is frm-testing.md.

Suggested corrections
-Before writing or modifying ANY code, read and follow the applicable rules from `.windsurf/rules/`:
+Before writing or modifying ANY code, read and follow the applicable rules from `.devin/rules/`:

-| Tests                    | `formidable/testing.md`                                                                                              |
+| Tests                    | `formidable/frm-testing.md`                                                                                          |
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Before writing or modifying ANY code, read and follow the applicable rules from `.devin/rules/`:

| File type                | Rules to read                                                                                                        |
| ------------------------ | -------------------------------------------------------------------------------------------------------------------- |
| `*.php`                  | `formidable/frm-php.md`, `wordpress/php.md`, `wordpress-vip/wpvip-security.md`, `wordpress-vip/wpvip-performance.md` |
| `*.js`, `*.jsx`, `*.mjs` | `formidable/frm-javascript.md`, `wordpress/javascript.md`, `wordpress-vip/wpvip-security.md`                         |
| `*.css`, `*.scss`        | `formidable/frm-css.md`                                                                                              |
| `*.html`                 | `wordpress/html.md`                                                                                                  |
| Block editor code        | `wordpress/block-editor.md`, `wordpress-vip/wpvip-block-editor.md`                                                   |
| UI/forms/user-facing     | `wordpress/accessibility.md`                                                                                         |
| Tests                    | `formidable/frm-testing.md`                                                                                          |
🧰 Tools
🪛 LanguageTool

[uncategorized] ~27-~27: The official name of this content management system is spelled with a capital “P”.
Context: ... | formidable/frm-php.md, wordpress/php.md, `wordpress-vip/wpvip-security....

(WORDPRESS)


[uncategorized] ~28-~28: The official name of this content management system is spelled with a capital “P”.
Context: ....mjs|formidable/frm-javascript.md, wordpress/javascript.md, wordpress-vip/wpvip-se...

(WORDPRESS)


[uncategorized] ~30-~30: The official name of this content management system is spelled with a capital “P”.
Context: ... | | *.html | wordpress/html.md ...

(WORDPRESS)


[uncategorized] ~31-~31: The official name of this content management system is spelled with a capital “P”.
Context: ... | | Block editor code | wordpress/block-editor.md, `wordpress-vip/wpvip-...

(WORDPRESS)


[uncategorized] ~32-~32: The official name of this content management system is spelled with a capital “P”.
Context: ... | | UI/forms/user-facing | wordpress/accessibility.md ...

(WORDPRESS)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.devin/skills/fix-bug/SKILL.md around lines 23 - 34, The table in
.devin/skills/fix-bug/SKILL.md references inconsistent rule paths and a wrong
test filename; update the entries that list `*.php`, `*.js`, `*.css`, `*.html`,
block editor, UI/forms, and Tests so they point to the current rule location
`.devin/rules/...` (not `.windsurf/rules/...`) and replace
`formidable/testing.md` with the correct `frm-testing.md` filename, ensuring
each referenced rule file name (e.g., `formidable/frm-php.md`,
`formidable/frm-javascript.md`, `formidable/frm-css.md`, `wordpress/html.md`,
`wordpress/accessibility.md`) matches the real files under `.devin/rules/`.
classes/controllers/FrmFieldsController.php (2)

1150-1151: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Validate json_encode result before using in attribute.

Line 1151 passes json_encode($product_field) directly to esc_attr() without checking for encoding failures. If json_encode() returns false (due to malformed UTF-8 or other encoding errors), the data-frmproduct attribute will be set to an empty string, potentially breaking JavaScript that expects valid JSON.

🛡️ Proposed fix
 } elseif ( $type === 'quantity' ) {
     $product_field               = FrmField::get_option( $field, 'product_field' );
-    $add_html['data-frmproduct'] = 'data-frmproduct="' . esc_attr( json_encode( $product_field ) ) . '"';
+    $encoded                     = json_encode( $product_field );
+    if ( false !== $encoded ) {
+        $add_html['data-frmproduct'] = 'data-frmproduct="' . esc_attr( $encoded ) . '"';
+    }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@classes/controllers/FrmFieldsController.php` around lines 1150 - 1151, The
code uses json_encode($product_field) directly when building
$add_html['data-frmproduct'], but json_encode can return false on failure;
update the FrmField::get_option handling so you encode into a variable, check
json_last_error() (or that the result !== false), and only add the
data-frmproduct attribute with esc_attr($encoded) when encoding succeeded
(otherwise either omit the attribute or set it to a safe fallback like '{}');
reference the existing $product_field, the json_encode call, esc_attr usage and
$add_html['data-frmproduct'] when making the change.

1174-1174: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add defensive check for $field['id'] existence.

Line 1174 accesses $field['id'] without verifying the key exists. If the $field array is incomplete or malformed, this will trigger a PHP notice.

🛡️ Proposed fix
- $field_obj = FrmFieldFactory::get_field_object( $field['id'] );
+ if ( ! isset( $field['id'] ) ) {
+     return 0;
+ }
+ 
+ $field_obj = FrmFieldFactory::get_field_object( $field['id'] );
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@classes/controllers/FrmFieldsController.php` at line 1174, Add a defensive
existence check before accessing $field['id'] in the call to
FrmFieldFactory::get_field_object: verify isset($field['id']) (or
array_key_exists) and handle the missing-key case (e.g., skip processing that
$field, log an error/warning, or set $field_obj to null) so that
FrmFieldFactory::get_field_object is only called with a valid id and $field_obj
is not created from a malformed $field.

}

if ( $echo ) {
echo $add_html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Variable $add_html might not be defined


A variable has been used but not defined, which may result in warnings during program execution. This can also cause bugs since the intended usage scope of the variable is not known.

self::add_pattern_attribute( $field, $add_html );
self::add_currency_field_attributes( $field, $add_html );

$add_html = apply_filters( 'frm_field_extra_html', $add_html, $field );
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Function apply_filters invoked with 3 parameters, 2 required


The function call is not valid, which will result in a fatal runtime error.

@@ -23,9 +24,11 @@

if ( $read_only ) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Variable $read_only might not be defined


A variable has been used but not defined, which may result in warnings during program execution. This can also cause bugs since the intended usage scope of the variable is not known.

<?php
} else {
?>
<select name="<?php echo esc_attr( $field_name ); ?>" id="<?php echo esc_attr( $html_id ); ?>" <?php do_action( 'frm_field_input_html', $field, true, $args ); ?>>
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Variable $field_name might not be defined


A variable has been used but not defined, which may result in warnings during program execution. This can also cause bugs since the intended usage scope of the variable is not known.

<?php
} else {
?>
<select name="<?php echo esc_attr( $field_name ); ?>" id="<?php echo esc_attr( $html_id ); ?>" <?php do_action( 'frm_field_input_html', $field, true, $args ); ?>>
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Variable $html_id might not be defined


A variable has been used but not defined, which may result in warnings during program execution. This can also cause bugs since the intended usage scope of the variable is not known.

@Crabcyborg Crabcyborg requested a review from garretlaxton June 5, 2026 17:22
Copy link
Copy Markdown

@garretlaxton garretlaxton left a comment

Choose a reason for hiding this comment

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

This works great!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants