Skip to content

Conversation

@arifulhoque7
Copy link
Contributor

@arifulhoque7 arifulhoque7 commented Sep 12, 2025

PR: Add Icon Support for Form Fields in WPUF Form Builder Close 1048 Related PR in pro

Description
This PR enhances the WP User Frontend (WPUF) form builder by introducing an icon option for form fields. Admins can now visually improve their forms by placing icons next to field labels or inside input fields (prefix/suffix). The feature is designed to boost usability, accessibility, and overall design consistency.

Key Features

  • Added "Field Icon" option in form builder settings for all fields.

  • Integration with Font Awesome 7 Free (supporting 2,806 icons).

  • Placement options:

    • No icon (default)
    • Left of label
    • Right of label
    • Inside input (prefix)
    • Inside input (suffix)
  • Icons render seamlessly on the frontend across all WPUF form types (post forms, registration forms, etc.).

  • Backward compatible (no changes for existing forms without icons).

Benefits

  • Enhances form aesthetics and modernizes UI.
  • Improves user experience by giving visual cues for field purposes (e.g., 📧 email, 📞 phone, 🔑 password).
  • Consistent with modern UI/UX patterns.

Considerations

  • Optional per field, so existing forms remain unaffected.
  • Icons load from Font Awesome CDN; minimal performance impact.
  • Works with both WPUF Free and Pro.
  • No additional color customization included (can be styled with theme/custom CSS).

Acceptance Criteria

  • Icons can be added or removed per field in the form builder.
  • Icons appear correctly on frontend forms (label & input placements).
  • No conflicts with themes or WPUF custom CSS.
  • Tested across WPUF Free and Pro modules.

Summary by CodeRabbit

  • New Features

    • Added icon selector with search and grid to choose field icons.
    • Support showing icons on form field labels, positioned left or right.
    • Default icons now auto-apply when enabling icons; new fields get icon defaults.
  • Bug Fixes

    • Removed duplicate name attributes on radio options for consistent grouping.
  • Style

    • New icon styling for labels and spacing/utilities.
  • Chores

    • Updated icon library and made icon sets configurable for the form builder.

arifulhoque7 and others added 2 commits September 11, 2025 18:42
- Add comprehensive Font Awesome 6.5.1 icon integration with 382 unique icons
- Implement icon selector component with search functionality and 4-column grid
- Add field icon options: Show Icon (Yes/No), Select Icon, Icon Position (Left/Right of label)
- Support icon display in form builder preview and frontend forms
- Add Vue.js reactivity fix for immediate icon functionality on new fields
- Include emerald-600 styling for form builder icons
- Ensure backward compatibility with all WPUF form types
- Fix duplicate key issues in Vue.js icon selector

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <[email protected]>
@coderabbitai
Copy link

coderabbitai bot commented Sep 12, 2025

Walkthrough

Adds per-field label icons with left/right positioning, replaces raw HTML icon injection with class-based elements, introduces an icon selector Vue component, initializes icon defaults in JS store, adds icon styles/utilities, updates Font Awesome asset, and reads icon config from JSON in PHP.

Changes

Cohort / File(s) Summary
Builder stage label rendering
admin/form-builder/assets/js/components/builder-stage/template.php, admin/form-builder/assets/js/components/builder-stage-v4-1/template.php
Replace v-html icon rendering with conditional left/right <i :class="[field.field_icon, 'wpuf-field-icon']"> gated by field.show_icon and field.icon_position.
Form templates & multitype updates
assets/js-templates/form-components.php
Replace field.icon HTML with field.field_icon <i> elements, add left/right placement, update multiselect/radio label areas; removes duplicate radio name attributes in templates; adds icon selector template (duplicate insertion present).
Admin icon selector component
admin/form-builder/assets/js/components/field-icon_selector/index.js, admin/form-builder/assets/js/components/field-icon_selector/template.php
Add field-icon_selector Vue component and template: searchable icon grid, select/clear, defaulting behavior, click-outside handling.
Public icon selector registration
assets/js/wpuf-form-builder-components.js, assets/js-templates/...
Register public field-icon_selector component mirroring admin behavior; integrate with store, defaultIcons, and icons list.
Field defaults and store mutations
admin/form-builder/assets/js/form-builder.js, assets/js/wpuf-form-builder.js
Ensure new fields and existing fields have show_icon, field_icon, and icon_position defaults on insertion and mount (guarded with hasOwnProperty / undefined checks).
Field radio cleanup (admin)
admin/form-builder/assets/js/components/field-radio/template.php
Remove duplicate :name="option_field.name" bindings on radio inputs, preserving the computed name binding.
Styles and utilities
admin/form-builder/assets/less/form-builder.less, assets/css/wpuf-form-builder.css, assets/css/admin/form-builder.css
Add .wpuf-field-label-icon .wpuf-field-icon rule (font-size, color, margin), introduce .wpuf-gap-1 and hover hover:wpuf-text-red-500 utility.
PHP: icon config & assets
includes/Admin/Forms/Admin_Form_Builder.php, includes/Assets.php
Add get_icon_config() to load icons/defaultIcons from JSON and localize to JS; switch Font Awesome asset from v4.7.0 to v7 all.min.css.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related issues

  • weDevsOfficial/wpuf-pro#1048 — Implements per-field icon support (new icon properties, selector UI, positioning), matching this PR's objectives.

Possibly related PRs

Suggested labels

needs: dev review

Suggested reviewers

  • sapayth

Poem

A hop, a nibble, an icon in sight,
Left or right I tuck it — snug and bright.
I picked a font and painted it green,
Swapped raw HTML for a tidy scene.
Thump! Forms gleam — a rabbit’s small delight. 🐇✨

Pre-merge checks and finishing touches

✅ 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 succinctly describes the main feature of dynamically adding field icons in the form builder, matching the PR’s purpose of introducing per-field icon support.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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.

@arifulhoque7 arifulhoque7 self-assigned this Sep 12, 2025
Copy link

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

🧹 Nitpick comments (50)
assets/js/wpuf-form-builder.js (1)

188-197: DRY the three property inits

Minor: consider replacing the repeated hasOwnProperty checks with ensureIconDefaults(payload.field) to keep both builder bundles in sync.

admin/form-builder/assets/js/form-builder.js (1)

188-197: Reduce duplication between the two builder bundles

Extract ensureIconDefaults* into a shared utility to prevent drift.

admin/form-builder/assets/js/components/field-icon_selector/template.php (3)

10-20: Add keyboard/a11y semantics to the trigger

Make the trigger operable via keyboard and screen readers.

-        <div
-            @click.stop="togglePicker"
+        <div
+            role="button"
+            tabindex="0"
+            aria-haspopup="dialog"
+            :aria-expanded="!!showIconPicker"
+            @keydown.enter.stop.prevent="togglePicker"
+            @keydown.space.stop.prevent="togglePicker"
+            @click.stop="togglePicker"
             class="wpuf-w-full wpuf-min-w-full !wpuf-py-[10px] !wpuf-px-[14px] wpuf-text-gray-700 wpuf-font-medium !wpuf-shadow-sm wpuf-border !wpuf-border-gray-300 !wpuf-rounded-[6px] hover:!wpuf-text-gray-700 wpuf-flex wpuf-justify-between wpuf-items-center !wpuf-text-base wpuf-cursor-pointer"
         >

23-28: Declare dialog semantics for the picker popover

Helps AT announce context; also set aria-label.

-        <div
+        <div
             v-if="showIconPicker"
             @click.stop
-            class="wpuf-absolute wpuf-bg-white wpuf-border wpuf-border-gray-300 wpuf-rounded-lg wpuf-w-full wpuf-z-50 wpuf-mt-1 wpuf-shadow-lg wpuf-right-0"
+            role="dialog"
+            aria-modal="true"
+            aria-label="Icon picker"
+            class="wpuf-absolute wpuf-bg-white wpuf-border wpuf-border-gray-300 wpuf-rounded-lg wpuf-w-full wpuf-z-50 wpuf-mt-1 wpuf-shadow-lg wpuf-right-0"

45-56: Listbox semantics and selection state; performance note

  • Mark the grid as a listbox and each item as an option with aria-selected.
  • Consider virtualized rendering to avoid mounting ~2.8k nodes at once (e.g., vue-virtual-scroll-list) and debounce search input.
-                <div v-if="filteredIcons.length > 0" class="wpuf-icon-grid" style="display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px;">
+                <div v-if="filteredIcons.length > 0" class="wpuf-icon-grid" role="listbox" style="display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px;">
                     <div
                         v-for="icon in filteredIcons"
                         :key="icon.class"
                         @click="selectIcon(icon.class)"
                         :class="['wpuf-icon-grid-item', { 'selected': value === icon.class }]"
+                        role="option"
+                        :aria-selected="value === icon.class"
                         :title="icon.name + ' - ' + icon.keywords"
                         style="padding: 10px 5px; text-align: center; border: 1px solid #e0e0e0; border-radius: 4px; cursor: pointer; transition: all 0.2s; min-height: 60px; display: flex; flex-direction: column; align-items: center; justify-content: center;"
                     >

Optional search debounce (script-level):

// created()
this.debouncedSet = _.debounce((v) => { this.searchTerm = v; }, 150);
assets/js-templates/form-components.php (3)

304-315: A11y: make clear button and toggle keyboard-accessible

The “clear” icon and chevron should be operable via keyboard and have labels.

-<i v-if="value" @click.stop="clearIcon" class="fa fa-times ..."></i>
+<i v-if="value"
+   role="button" tabindex="0" aria-label="<?php echo esc_attr__('Clear icon', 'wp-user-frontend'); ?>"
+   @click.stop="clearIcon"
+   @keydown.enter.stop.prevent="clearIcon"
+   @keydown.space.stop.prevent="clearIcon"
+   class="fa fa-times ..."></i>

-<i :class="showIconPicker ? 'fa-angle-up' : 'fa-angle-down'" class="fa wpuf-text-base"></i>
+<i :class="showIconPicker ? 'fa-angle-up' : 'fa-angle-down'"
+   role="button" tabindex="0" :aria-label="showIconPicker ? '<?php echo esc_attr__('Collapse', 'wp-user-frontend'); ?>' : '<?php echo esc_attr__('Expand', 'wp-user-frontend'); ?>'"
+   @keydown.enter.stop.prevent="togglePicker"
+   @keydown.space.stop.prevent="togglePicker"
+   class="fa wpuf-text-base"></i>

339-351: A11y: grid items should be buttons (focusable, labeled)

Use with aria-pressed to indicate selection and support keyboard selection.

-<div
+<button type="button"
   v-for="icon in filteredIcons"
   :key="icon.class"
   @click="selectIcon(icon.class)"
-  :class="['wpuf-icon-grid-item', { 'selected': value === icon.class }]"
+  :class="['wpuf-icon-grid-item', { 'selected': value === icon.class }]"
   :title="icon.name + ' - ' + icon.keywords"
+  :aria-label="icon.name"
+  :aria-pressed="value === icon.class"
   style="padding: 10px 5px; text-align: center; border: 1px solid #e0e0e0; border-radius: 4px; cursor: pointer; transition: all 0.2s; min-height: 60px; display: flex; flex-direction: column; align-items: center; justify-content: center;"
 >
   <i :class="icon.class" style="font-size: 18px; margin-bottom: 4px; color: #555;"></i>
   <div style="font-size: 10px; color: #666; line-height: 1.2; word-break: break-word; max-width: 100%;">{{ icon.name }}</div>
-</div>
+</button>

21-31: Spacing on right_label icons is asymmetrical

Global CSS adds margin-right on .wpuf-field-icon, which also affects right_label. Prefer removing icon-level margin and rely on container spacing (wpuf-mr-1 / wpuf-ml-2), or add position-specific rules.

Also applies to: 120-134

admin/form-builder/assets/less/form-builder.less (2)

1540-1546: Make icon spacing position-aware (avoid double spacing on right_label)

Current rule adds margin-right for all icons, but right_label already uses a left margin on the wrapper. Either remove the margin here or split per-position.

Option A (simplest): remove margin-right and rely on wrapper spacing.

 .wpuf-field-label-icon .wpuf-field-icon {
     font-size: 20px;
     color: #059669; /* emerald-600 */
-    margin-right: 6px;
 }

Option B: add directional selectors if you can mark position, e.g., .is-left/.is-right on the wrapper.

.wpuf-field-label-icon.is-left .wpuf-field-icon { margin-right: 6px; }
.wpuf-field-label-icon.is-right .wpuf-field-icon { margin-left: 6px; }

1540-1546: Consider theming via CSS variables instead of hard-coded color

Use a variable (with fallback) to make the icon color overridable.

-.wpuf-field-label-icon .wpuf-field-icon {
-    font-size: 20px;
-    color: #059669; /* emerald-600 */
+.wpuf-field-label-icon .wpuf-field-icon {
+    font-size: 20px;
+    color: var(--wpuf-field-icon-color, #059669);
assets/css/wpuf-form-builder.css (2)

1240-1246: Compiled CSS mirrors LESS change; avoid manual edits and recompile after LESS updates

Confirm this file is generated from LESS and not hand-edited. After adjusting spacing/color in LESS, re-run the build to update this output.


1240-1246: Same spacing concern as in LESS

If you keep the generic rule, it will add margin-right to right_label too. Prefer removing margin-right here after updating the LESS and recompiling.

assets/vendor/font-awesome-7/scss/_functions.scss (1)

5-8: Deduplicate quoting logic by reusing fa-content() elsewhere.

Since fa-content($var) exists, replace repeated string.unquote("\"#{ ... }\"") in other partials (e.g., _shims.scss) with this helper to reduce code size and drift.

Example change inside callers:

-#{v.$icon-property}: string.unquote("\"#{ v.$var-envelope }\"");
+#{v.$icon-property}: fa-content(v.$var-envelope);
assets/vendor/font-awesome-7/metadata/sponsors.yml (1)

1-20: Large metadata payload — exclude from production package.

This file isn’t needed at runtime. Exclude assets/vendor/font-awesome-7/metadata/** from the plugin release (e.g., .distignore) to cut zip size.

If you want, I can propose a .distignore snippet.

assets/vendor/font-awesome-7/scss/_shims.scss (3)

4-20: Use fa-content() helper to reduce repetition.

Every occurrence of string.unquote("\"#{ ... }\"") can instead call fa-content(...). This shrinks source and avoids quoting bugs.

Apply pattern:

-#{v.$icon-property}: string.unquote("\"#{ v.$var-circle-down }\"");
+#{v.$icon-property}: fa-content(v.$var-circle-down);

8-16: Font family/weight declarations: keep minimal and correct.

For regular glyphs you set font-family: 'Font Awesome 7 Free'; font-weight: 400; which is correct. Where the same selector appears twice (base + content), consider merging into one block to cut CSS size at compile time.


197-210: Avoid double-shim loading.

You also ship css/v4-shims.min.css. Ensure only one shim path is enqueued (compiled CSS or this SCSS output), not both.

assets/vendor/font-awesome-7/metadata/shims.yml (1)

1-18: Runtime need vs. package weight.

This mapping is useful for build-time tooling but not required at runtime if you already ship v4 CSS shims. Exclude from production zips to save space.

assets/vendor/font-awesome-7/scss/fontawesome.scss (1)

1-5: Match Sass toolchain to @use-based partials.

Same Dart Sass requirement applies here. Confirm the build compiles SCSS only for dev and excludes .scss from production bundles.

assets/vendor/font-awesome-7/css/v4-shims.min.css (1)

1-6: Load shims only where needed.

V4 shims are heavy. Load in admin/builder UI only if legacy classes are used; avoid enqueueing on the frontend to reduce CSS payload.

assets/vendor/font-awesome-7/scss/v4-shims.scss (1)

1-11: Clarify load source: CDN vs vendored files.

PR text says “Icons load from the Font Awesome CDN,” but this repo vendors FA7 (including v4 shims). Please confirm the single source of truth and avoid double-loading (CDN + local). If CDN is desired, add SRI + crossorigin and make local fallback optional via a filter; if local is desired, remove CDN enqueues.

assets/vendor/font-awesome-7/scss/_icons.scss (1)

10-14: Avoid duplicating icon class generation.

This @each emits per-icon classes that appear to mirror what the shipped minified CSS already provides (e.g., .fa-... { --fa:"..."} in brands/regular/solid). Consider not compiling this file to keep CSS size down, and rely on the packaged minified CSS.

assets/vendor/font-awesome-7/css/regular.min.css (1)

6-6: Font loading UX — override Font Awesome's font-display to swap (do not edit vendor files).

assets/vendor/font-awesome-7/css/regular.min.css declares an @font-face with font-display:block (src: ../webfonts/fa-regular-400.woff2) which can cause FOIT. Add a small CSS file loaded after vendor CSS that copies that @font-face and changes font-display:block → font-display:swap.

assets/vendor/font-awesome-7/css/v5-font-face.css (1)

6-23: Mitigate conflicts with sites already loading FA5.

These @font-face families (“Font Awesome 5 Free/Brands”) match common theme/plugin loads. Only enqueue when needed (e.g., when v5 compatibility is explicitly enabled), and gate with wp_style_is-like checks to avoid duplicate families and specificity fights.

assets/vendor/font-awesome-7/css/v4-font-face.css (1)

6-27: Scope v4 compatibility assets tightly.

The “FontAwesome” family name collides with FA4 on many sites. Recommend only enqueueing this (and v4-shims) when v4 icon names are actually used, and preferably in admin/builder, not globally on the frontend.

assets/vendor/font-awesome-7/css/solid.min.css (1)

6-6: Consider font-display: swap for Solid too.

Same rationale as Regular. Implement via a small override stylesheet rather than modifying vendor files.

assets/vendor/font-awesome-7/css/brands.min.css (1)

6-6: Load only when necessary and dedupe with existing FA on the site.

This is a large asset and commonly clashes with themes/plugins already loading FA. Ensure:

  • Only enqueue on the builder screens and on frontend pages where fields have icons.
  • Use the provided conflict-detection script (and/or handles checks) to avoid double-loading.
  • Reconcile CDN vs local loading choice across the plugin.
    Also confirm license file inclusion and attribution requirements are satisfied in plugin readme/changelog.
assets/vendor/font-awesome-7/css/v5-font-face.min.css (1)

6-6: font-display: block may hurt LCP.

Prefer swap or optional to avoid FOIT. If you can’t edit vendored min CSS, override via your own @font-face declarations or source from SCSS where v.$font-display is configurable.

assets/vendor/font-awesome-7/css/brands.css (2)

11-17: Consider font-display swap for better UX.

If you control the build for this file, use font-display: swap to reduce FOIT. Otherwise, leave as-is but consider an override.


23-28: Global .fab/.fa-brands may collide with site-wide FA. Scope if possible.

If themes already load Font Awesome, these base classes can conflict. Prefer scoping all FA rules under a WPUF wrapper (e.g., .wpuf) during enqueue or via a build step to minimize global overrides.

assets/vendor/font-awesome-7/scss/_list.scss (1)

13-19: Add physical fallbacks for older browsers.

inline-start/end are broadly supported now, but adding harmless left/right fallbacks improves resilience.

Apply:

 .#{v.$css-prefix}-li {
-  inset-inline-start: calc(-1 * var(--#{v.$css-prefix}-li-width, #{v.$li-width}));
+  left: calc(-1 * var(--#{v.$css-prefix}-li-width, #{v.$li-width}));
+  inset-inline-start: calc(-1 * var(--#{v.$css-prefix}-li-width, #{v.$li-width}));
   position: absolute;
   text-align: center;
   width: var(--#{v.$css-prefix}-li-width, #{v.$li-width});
   line-height: inherit;
 }

And in the UL rule:

 .#{v.$css-prefix}-ul {
   list-style-type: none;
-  margin-inline-start: var(--#{v.$css-prefix}-li-margin, #{v.$li-margin});
+  margin-left: var(--#{v.$css-prefix}-li-margin, #{v.$li-margin});
+  margin-inline-start: var(--#{v.$css-prefix}-li-margin, #{v.$li-margin});
   padding-inline-start: 0;
assets/vendor/font-awesome-7/scss/_pulled.scss (2)

5-9: Add physical float fallback.

For maximal resilience, include left/right before inline-start/end.

Apply:

 .#{v.$css-prefix}-pull-left,
 .#{v.$css-prefix}-pull-start {
-  float: inline-start;
+  float: left;
+  float: inline-start;
   margin-inline-end: var(--#{v.$css-prefix}-pull-margin, #{v.$pull-margin});
 }

11-15: Symmetric fallback on right side.

Apply:

 .#{v.$css-prefix}-pull-right,
 .#{v.$css-prefix}-pull-end {
-  float: inline-end;
+  float: right;
+  float: inline-end;
   margin-inline-start: var(--#{v.$css-prefix}-pull-margin, #{v.$pull-margin});
 }
assets/vendor/font-awesome-7/scss/brands.scss (1)

30-34: SCSS icon map expansion is fine; watch CSS size.

If bundle size is a concern, consider limiting to used icons or loading from CDN with subsetting.

assets/vendor/font-awesome-7/scss/_core.scss (1)

17-28: Global selector includes .fa — potential conflict.

Targeting .fa (and .fas/.far/.fab) site-wide can clash with any theme-loaded Font Awesome. If feasible, scope under a WPUF wrapper (e.g., .wpuf .fa, .wpuf .fas, etc.) during build to avoid global overrides.

assets/vendor/font-awesome-7/scss/_bordered.scss (1)

5-7: Fix minor doc typos in the deprecation notice.

Tighten wording and stray characters to avoid confusion in vendor docs.

-/* Heads Up: Bordered Icons will not be supported in the future!
-  - This feature will be deprecated in the next major release of Font Awesome (v8)!
-  - You may continue to use it in this version *v7), but it will not be supported in Font Awesome v8.
+/* Heads Up: Bordered Icons will not be supported in the future.
+  - This feature will be deprecated in the next major release of Font Awesome (v8).
+  - You may continue to use it in this version (v7), but it will not be supported in Font Awesome v8.
assets/vendor/font-awesome-7/css/svg.min.css (1)

1-6: License header present — keep vendor file unmodified.

Header matches FA Free 7.0.1. Ensure LICENSE files are included at the vendor root in the repo/package.

If distributing on wp.org, ensure license files are shipped and third-party notices updated.

assets/vendor/font-awesome-7/css/v4-shims.css (1)

1-5: Massive v4 shim table — consider not enqueuing by default.

Unless you rely on legacy v4 class names, avoid loading this on the frontend to save bytes. Gate it behind a “compat” flag or load only in admin where previews might need it.

I can propose an enqueue strategy that conditionally loads shims only when legacy classes are detected in builder-rendered HTML.

assets/vendor/font-awesome-7/css/svg-with-js.min.css (1)

6-6: Payload control.

This file is sizable. Only enqueue when forms with icons are rendered, and avoid loading both svg.min.css and svg-with-js.min.css simultaneously unless required.

assets/vendor/font-awesome-7/css/svg.css (2)

37-44: Default icon width (1.25em) can misalign label-adjacent icons.

For tighter alignment next to labels, consider overriding width to 1em inside the WPUF field-icon wrapper rather than editing vendor CSS:

/* in plugin/theme stylesheet, scoped to WPUF */
.wpuf-field-icon .svg-inline--fa { --fa-width: 1em; }

75-82: Avoid loading multiple FA rendering paths.

You appear to include both svg.css and svg-with-js.css elsewhere in the PR. Pick one rendering approach (SVG-with-JS vs classic webfont) to prevent duplicate rules and conflicting defaults.

assets/vendor/font-awesome-7/css/svg-with-js.css (2)

1-5: Ship minified in production; gate on SCRIPT_DEBUG.

Commit includes non-minified CSS. Please enqueue the .min.css in production and the readable file only when SCRIPT_DEBUG is true.

I can provide a small enqueue snippet if helpful.


289-377: Animation classes: avoid in forms by default.

Animated icons (beat, bounce, shake, spin, etc.) can be distracting in forms. Ensure the builder doesn’t enable animation classes by default; keep them opt-in if exposed.

assets/vendor/font-awesome-7/css/regular.css (1)

1-5: Include upstream license file in vendor directory.

Header references FA Free license; ensure the corresponding LICENSE/COPYRIGHT files are committed alongside the vendor assets to meet redistribution requirements.

assets/vendor/font-awesome-7/scss/_rotated-flipped.scss (1)

1-33: Exclude SCSS from the distributable to trim plugin size.

SCSS sources aren’t needed on production sites. Add the vendor SCSS path to your packaging ignore (.distignore/.npmignore) so only compiled CSS ships.

Suggested ignore entries (add to your packaging ignore file):

  • assets/vendor/font-awesome-7/scss/
assets/vendor/font-awesome-7/js/v4-shims.js (2)

572-579: Minify for production; this build treats PRODUCTION as false in browsers.

process.env.NODE_ENV will be undefined in WordPress, so PRODUCTION resolves to false and bunker() won’t swallow errors. Prefer enqueuing the minified production build (v4-shims.min.js) in production via SCRIPT_DEBUG gating.


628-634: Global namespace collision risk with other FA versions.

This registers on window.FONT_AWESOME. If themes/other plugins already load FA (v4–v7), shims may conflict. Only enqueue shims when needed and consider detecting an existing FA instance before enqueuing.

assets/vendor/font-awesome-7/js/conflict-detection.js (3)

646-656: Detector misses Font Awesome 7 families; expand the regex.

The computedStyle check only matches “FontAwesome” and “Font Awesome 5/6”, so FA7 loads won’t be flagged. Suggest including FA7 families to avoid false negatives.

-            if (!!fontFamily.match(/FontAwesome/) || !!fontFamily.match(/Font Awesome [56]/)) {
+            if (
+              /FontAwesome/.test(fontFamily) ||
+              /Font Awesome (?:5|6|7)/.test(fontFamily) ||
+              /Font Awesome 7 (?:Free|Brands)/.test(fontFamily)
+            ) {

1429-1433: Avoid auto-running heavy conflict scans; gate behind opt‑in attribute.

Spawning hidden iframes for every link/style on all pages can be noisy/expensive. Make autostart opt‑in to keep production pages clean.

-  bunker(function () {
-    if (IS_BROWSER && IS_DOM) {
-      conflictDetection(window.FontAwesomeDetection.report);
-    }
-  });
+  bunker(function () {
+    if (
+      IS_BROWSER &&
+      IS_DOM &&
+      DOCUMENT.currentScript &&
+      DOCUMENT.currentScript.hasAttribute('data-fa-detection-autostart')
+    ) {
+      conflictDetection(window.FontAwesomeDetection.report);
+    }
+  });

72-80: Biome “noFunctionAssign” on Babel helper is from vendored upstream; ignore vendor in lint.

The self‑reassigning _typeof helper triggers Biome’s noFunctionAssign. Prefer excluding vendor paths from lint instead of patching upstream.

Add/adjust Biome config to ignore vendor assets:

{
  "$schema": "https://biomejs.dev/schemas/1.7.3/schema.json",
  "files": {
    "ignore": ["assets/vendor/**"]
  }
}

If you’d rather keep linting enabled, add a file header directive just above line 1:

/* biome-ignore lint/suspicious/noFunctionAssign: upstream Babel helper in vendored file */
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1d7b9b1 and 901641a.

⛔ Files ignored due to path filters (232)
  • assets/vendor/font-awesome-7/js/all.min.js is excluded by !**/*.min.js
  • assets/vendor/font-awesome-7/js/brands.min.js is excluded by !**/*.min.js
  • assets/vendor/font-awesome-7/js/conflict-detection.min.js is excluded by !**/*.min.js
  • assets/vendor/font-awesome-7/js/fontawesome.min.js is excluded by !**/*.min.js
  • assets/vendor/font-awesome-7/js/regular.min.js is excluded by !**/*.min.js
  • assets/vendor/font-awesome-7/js/solid.min.js is excluded by !**/*.min.js
  • assets/vendor/font-awesome-7/js/v4-shims.min.js is excluded by !**/*.min.js
  • assets/vendor/font-awesome-7/sprites-full/brands.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/sprites-full/regular.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/sprites-full/solid.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/sprites/brands.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/sprites/regular.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/sprites/solid.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/11ty.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/42-group.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/500px.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/accessible-icon.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/accusoft.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/adn.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/adversal.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/affiliatetheme.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/airbnb.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/algolia.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/alipay.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/amazon-pay.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/amazon.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/amilia.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/android.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/angellist.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/angrycreative.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/angular.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/app-store-ios.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/app-store.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/apper.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/apple-pay.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/apple.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/artstation.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/asymmetrik.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/atlassian.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/audible.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/autoprefixer.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/avianex.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/aviato.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/aws.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/bandcamp.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/battle-net.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/behance-square.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/behance.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/bilibili.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/bimobject.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/bitbucket.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/bitcoin.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/bity.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/black-tie.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/blackberry.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/blogger-b.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/blogger.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/bluesky.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/bluetooth-b.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/bluetooth.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/bootstrap.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/bots.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/brave-reverse.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/brave.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/btc.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/buffer.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/buromobelexperte.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/buy-n-large.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/buysellads.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/canadian-maple-leaf.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/cash-app.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/cc-amazon-pay.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/cc-amex.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/cc-apple-pay.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/cc-diners-club.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/cc-discover.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/cc-jcb.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/cc-mastercard.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/cc-paypal.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/cc-stripe.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/cc-visa.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/centercode.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/centos.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/chrome.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/chromecast.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/cloudflare.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/cloudscale.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/cloudsmith.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/cloudversify.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/cmplid.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/codepen.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/codiepie.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/confluence.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/connectdevelop.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/contao.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/cotton-bureau.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/cpanel.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/creative-commons-by.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/creative-commons-nc-eu.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/creative-commons-nc-jp.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/creative-commons-nc.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/creative-commons-nd.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/creative-commons-pd-alt.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/creative-commons-pd.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/creative-commons-remix.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/creative-commons-sa.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/creative-commons-sampling-plus.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/creative-commons-sampling.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/creative-commons-share.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/creative-commons-zero.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/creative-commons.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/critical-role.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/css.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/css3-alt.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/css3.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/cuttlefish.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/d-and-d-beyond.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/d-and-d.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/dailymotion.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/dart-lang.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/dashcube.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/debian.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/deezer.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/delicious.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/deploydog.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/deskpro.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/dev.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/deviantart.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/dhl.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/diaspora.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/digg.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/digital-ocean.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/discord.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/discourse.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/disqus.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/dochub.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/docker.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/draft2digital.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/dribbble-square.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/dribbble.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/dropbox.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/drupal.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/duolingo.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/dyalog.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/earlybirds.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/ebay.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/edge-legacy.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/edge.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/elementor.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/eleventy.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/ello.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/ember.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/empire.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/envira.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/erlang.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/ethereum.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/etsy.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/evernote.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/expeditedssl.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/facebook-f.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/facebook-messenger.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/facebook-square.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/facebook.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/fantasy-flight-games.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/fedex.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/fedora.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/figma.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/files-pinwheel.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/firefox-browser.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/firefox.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/first-order-alt.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/first-order.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/firstdraft.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/flickr.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/flipboard.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/flutter.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/fly.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/font-awesome-alt.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/font-awesome-flag.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/font-awesome-logo-full.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/font-awesome.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/fonticons-fi.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/fonticons.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/fort-awesome-alt.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/fort-awesome.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/forumbee.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/foursquare.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/free-code-camp.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/freebsd.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/fulcrum.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/galactic-republic.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/galactic-senate.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/get-pocket.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/gg-circle.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/gg.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/git-alt.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/git-square.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/git.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/github-alt.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/github-square.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/github.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/gitkraken.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/gitlab-square.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/gitlab.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/gitter.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/glide-g.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/glide.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/gofore.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/golang.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/goodreads-g.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/goodreads.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/google-drive.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/google-pay.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/google-play.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/google-plus-g.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/google-plus-square.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/google-plus.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/google-scholar.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/google-wallet.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/google.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/gratipay.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/grav.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/gripfire.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/grunt.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/guilded.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/gulp.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/hacker-news-square.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/hacker-news.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/hackerrank.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/hashnode.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/hips.svg is excluded by !**/*.svg
  • assets/vendor/font-awesome-7/svgs-full/brands/hire-a-helper.svg is excluded by !**/*.svg
📒 Files selected for processing (52)
  • admin/form-builder/assets/js/components/builder-stage-v4-1/template.php (1 hunks)
  • admin/form-builder/assets/js/components/builder-stage/template.php (1 hunks)
  • admin/form-builder/assets/js/components/field-icon_selector/template.php (1 hunks)
  • admin/form-builder/assets/js/components/field-radio/template.php (0 hunks)
  • admin/form-builder/assets/js/form-builder.js (1 hunks)
  • admin/form-builder/assets/less/form-builder.less (1 hunks)
  • assets/css/admin/form-builder.css (2 hunks)
  • assets/css/wpuf-form-builder.css (1 hunks)
  • assets/js-templates/form-components.php (3 hunks)
  • assets/js/wpuf-form-builder.js (1 hunks)
  • assets/vendor/font-awesome-7/LICENSE.txt (1 hunks)
  • assets/vendor/font-awesome-7/css/all.min.css (1 hunks)
  • assets/vendor/font-awesome-7/css/brands.css (1 hunks)
  • assets/vendor/font-awesome-7/css/brands.min.css (1 hunks)
  • assets/vendor/font-awesome-7/css/fontawesome.min.css (1 hunks)
  • assets/vendor/font-awesome-7/css/regular.css (1 hunks)
  • assets/vendor/font-awesome-7/css/regular.min.css (1 hunks)
  • assets/vendor/font-awesome-7/css/solid.css (1 hunks)
  • assets/vendor/font-awesome-7/css/solid.min.css (1 hunks)
  • assets/vendor/font-awesome-7/css/svg-with-js.css (1 hunks)
  • assets/vendor/font-awesome-7/css/svg-with-js.min.css (1 hunks)
  • assets/vendor/font-awesome-7/css/svg.css (1 hunks)
  • assets/vendor/font-awesome-7/css/svg.min.css (1 hunks)
  • assets/vendor/font-awesome-7/css/v4-font-face.css (1 hunks)
  • assets/vendor/font-awesome-7/css/v4-font-face.min.css (1 hunks)
  • assets/vendor/font-awesome-7/css/v4-shims.css (1 hunks)
  • assets/vendor/font-awesome-7/css/v4-shims.min.css (1 hunks)
  • assets/vendor/font-awesome-7/css/v5-font-face.css (1 hunks)
  • assets/vendor/font-awesome-7/css/v5-font-face.min.css (1 hunks)
  • assets/vendor/font-awesome-7/js/conflict-detection.js (1 hunks)
  • assets/vendor/font-awesome-7/js/v4-shims.js (1 hunks)
  • assets/vendor/font-awesome-7/metadata/shims.yml (1 hunks)
  • assets/vendor/font-awesome-7/metadata/sponsors.yml (1 hunks)
  • assets/vendor/font-awesome-7/scss/_animated.scss (1 hunks)
  • assets/vendor/font-awesome-7/scss/_bordered.scss (1 hunks)
  • assets/vendor/font-awesome-7/scss/_core.scss (1 hunks)
  • assets/vendor/font-awesome-7/scss/_fa.scss (1 hunks)
  • assets/vendor/font-awesome-7/scss/_functions.scss (1 hunks)
  • assets/vendor/font-awesome-7/scss/_icons.scss (1 hunks)
  • assets/vendor/font-awesome-7/scss/_list.scss (1 hunks)
  • assets/vendor/font-awesome-7/scss/_mixins.scss (1 hunks)
  • assets/vendor/font-awesome-7/scss/_pulled.scss (1 hunks)
  • assets/vendor/font-awesome-7/scss/_rotated-flipped.scss (1 hunks)
  • assets/vendor/font-awesome-7/scss/_shims.scss (1 hunks)
  • assets/vendor/font-awesome-7/scss/_sizing.scss (1 hunks)
  • assets/vendor/font-awesome-7/scss/_stacked.scss (1 hunks)
  • assets/vendor/font-awesome-7/scss/_widths.scss (1 hunks)
  • assets/vendor/font-awesome-7/scss/brands.scss (1 hunks)
  • assets/vendor/font-awesome-7/scss/fontawesome.scss (1 hunks)
  • assets/vendor/font-awesome-7/scss/regular.scss (1 hunks)
  • assets/vendor/font-awesome-7/scss/solid.scss (1 hunks)
  • assets/vendor/font-awesome-7/scss/v4-shims.scss (1 hunks)
💤 Files with no reviewable changes (1)
  • admin/form-builder/assets/js/components/field-radio/template.php
🧰 Additional context used
🪛 Biome (2.1.2)
assets/vendor/font-awesome-7/js/conflict-detection.js

[error] 72-72: Do not reassign a function declaration.

Reassigned here.

Use a local variable instead.

(lint/suspicious/noFunctionAssign)

Comment on lines +27 to +30
<span v-if="field.show_icon === 'yes' && field.field_icon && field.icon_position === 'left_label'"
class="wpuf-field-label-icon wpuf-inline-flex wpuf-items-center wpuf-mr-1">
<i :class="[field.field_icon, 'wpuf-field-icon']"></i>
</span>
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Hide label icons when the label itself is hidden; add aria-hidden

Currently icons render even when the label is invisible. Gate by !is_invisible(field) and mark decorative icons as aria-hidden.

-                    <span v-if="field.show_icon === 'yes' && field.field_icon && field.icon_position === 'left_label'" 
+                    <span v-if="field.show_icon === 'yes' && field.field_icon && field.icon_position === 'left_label' && !is_invisible(field)" 
                           class="wpuf-field-label-icon wpuf-inline-flex wpuf-items-center wpuf-mr-1">
-                          <i :class="[field.field_icon, 'wpuf-field-icon']"></i>
+                          <i :class="[field.field_icon, 'wpuf-field-icon']" aria-hidden="true"></i>
                     </span>
📝 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.

Suggested change
<span v-if="field.show_icon === 'yes' && field.field_icon && field.icon_position === 'left_label'"
class="wpuf-field-label-icon wpuf-inline-flex wpuf-items-center wpuf-mr-1">
<i :class="[field.field_icon, 'wpuf-field-icon']"></i>
</span>
<span v-if="field.show_icon === 'yes' && field.field_icon && field.icon_position === 'left_label' && !is_invisible(field)"
class="wpuf-field-label-icon wpuf-inline-flex wpuf-items-center wpuf-mr-1">
<i :class="[field.field_icon, 'wpuf-field-icon']" aria-hidden="true"></i>
</span>
🤖 Prompt for AI Agents
In admin/form-builder/assets/js/components/builder-stage-v4-1/template.php
around lines 27 to 30, the label icon is rendered even when the label is
invisible; update the v-if to also check that the field is not invisible (i.e.,
&& !is_invisible(field)) so icons are gated by the label visibility, and mark
the icon element as decorative by adding aria-hidden="true" to the <i> element
so screen readers ignore it.

Comment on lines 31 to 37
<label
v-if="!is_invisible(field)"
:for="'wpuf-' + field.name ? field.name : 'cls'"
class="wpuf-block wpuf-text-sm wpuf-font-medium wpuf-leading-6 wpuf-text-gray-900">
{{ field.label }} <span v-if="field.required && 'yes' === field.required"
class="required">*</span>
</label>
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix ternary precedence in the label “for” binding

The current expression always evaluates the truthy left side of the ternary and returns field.name without the wpuf- prefix.

-                        :for="'wpuf-' + field.name ? field.name : 'cls'"
+                        :for="'wpuf-' + (field.name ? field.name : 'cls')"
📝 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.

Suggested change
<label
v-if="!is_invisible(field)"
:for="'wpuf-' + field.name ? field.name : 'cls'"
class="wpuf-block wpuf-text-sm wpuf-font-medium wpuf-leading-6 wpuf-text-gray-900">
{{ field.label }} <span v-if="field.required && 'yes' === field.required"
class="required">*</span>
</label>
<label
v-if="!is_invisible(field)"
:for="'wpuf-' + (field.name ? field.name : 'cls')"
class="wpuf-block wpuf-text-sm wpuf-font-medium wpuf-leading-6 wpuf-text-gray-900">
{{ field.label }} <span v-if="field.required && 'yes' === field.required"
class="required">*</span>
</label>
🤖 Prompt for AI Agents
In admin/form-builder/assets/js/components/builder-stage-v4-1/template.php
around lines 31 to 37, the ternary operator in the :for binding is evaluated
before the string concatenation so it returns field.name without the "wpuf-"
prefix; change the expression so the ternary only decides which base value to
use and then prefix with "wpuf-" (e.g. either wrap the ternary in parentheses
after the prefix or apply the ternary to the whole result), ensuring the final
value is "wpuf-"+field.name when field.name is truthy and "cls" otherwise.

Comment on lines +38 to 41
<span v-if="field.show_icon === 'yes' && field.field_icon && field.icon_position === 'right_label'"
class="wpuf-field-label-icon wpuf-inline-flex wpuf-items-center wpuf-ml-2">
<i :class="[field.field_icon, 'wpuf-field-icon']"></i>
</span>
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Symmetry for right-aligned icon: respect label visibility; aria-hidden

Match the left icon fix.

-                    <span v-if="field.show_icon === 'yes' && field.field_icon && field.icon_position === 'right_label'" 
+                    <span v-if="field.show_icon === 'yes' && field.field_icon && field.icon_position === 'right_label' && !is_invisible(field)" 
                           class="wpuf-field-label-icon wpuf-inline-flex wpuf-items-center wpuf-ml-2">
-                          <i :class="[field.field_icon, 'wpuf-field-icon']"></i>
+                          <i :class="[field.field_icon, 'wpuf-field-icon']" aria-hidden="true"></i>
                     </span>
📝 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.

Suggested change
<span v-if="field.show_icon === 'yes' && field.field_icon && field.icon_position === 'right_label'"
class="wpuf-field-label-icon wpuf-inline-flex wpuf-items-center wpuf-ml-2">
<i :class="[field.field_icon, 'wpuf-field-icon']"></i>
</span>
<span v-if="field.show_icon === 'yes' && field.field_icon && field.icon_position === 'right_label' && !is_invisible(field)"
class="wpuf-field-label-icon wpuf-inline-flex wpuf-items-center wpuf-ml-2">
<i :class="[field.field_icon, 'wpuf-field-icon']" aria-hidden="true"></i>
</span>
🤖 Prompt for AI Agents
In admin/form-builder/assets/js/components/builder-stage-v4-1/template.php
around lines 38 to 41, the right-aligned label icon currently doesn't respect
label visibility nor mark the icon as decorative; update the span's v-if to also
require the label to be visible (e.g., include the same field.show_label ===
'yes' check used for the left icon) and add aria-hidden="true" to the <i>
element so the icon is omitted from accessibility tree when decorative.

Comment on lines +20 to +23
<span v-if="field.show_icon === 'yes' && field.field_icon && field.icon_position === 'left_label'"
class="wpuf-field-label-icon wpuf-inline-flex wpuf-items-center wpuf-mr-1">
<i :class="[field.field_icon, 'wpuf-field-icon']"></i>
</span>
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Hide icons when label is hidden; add aria-hidden

Match v4-1 fixes for left icon.

-                <span v-if="field.show_icon === 'yes' && field.field_icon && field.icon_position === 'left_label'" 
+                <span v-if="field.show_icon === 'yes' && field.field_icon && field.icon_position === 'left_label' && !is_invisible(field)" 
                       class="wpuf-field-label-icon wpuf-inline-flex wpuf-items-center wpuf-mr-1">
-                      <i :class="[field.field_icon, 'wpuf-field-icon']"></i>
+                      <i :class="[field.field_icon, 'wpuf-field-icon']" aria-hidden="true"></i>
                 </span>
📝 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.

Suggested change
<span v-if="field.show_icon === 'yes' && field.field_icon && field.icon_position === 'left_label'"
class="wpuf-field-label-icon wpuf-inline-flex wpuf-items-center wpuf-mr-1">
<i :class="[field.field_icon, 'wpuf-field-icon']"></i>
</span>
<span v-if="field.show_icon === 'yes' && field.field_icon && field.icon_position === 'left_label' && !is_invisible(field)"
class="wpuf-field-label-icon wpuf-inline-flex wpuf-items-center wpuf-mr-1">
<i :class="[field.field_icon, 'wpuf-field-icon']" aria-hidden="true"></i>
</span>
🤖 Prompt for AI Agents
In admin/form-builder/assets/js/components/builder-stage/template.php around
lines 20 to 23, the left-side icon is rendered regardless of whether the label
is hidden and lacks an aria-hidden attribute; update the v-if to also require
the label be visible (e.g. add a check such as field.label_hidden !== 'yes' or
field.hide_label !== 'yes' to the existing condition) so the icon is not shown
when the label is hidden, and add aria-hidden="true" to the <i> element to mark
the icon as decorative.

Comment on lines 24 to 26
<label v-if="!is_invisible(field)" :for="'wpuf-' + field.name ? field.name : 'cls'">
{{ field.label }} <span v-if="field.required && 'yes' === field.required" class="required">*</span>
</label>
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix ternary precedence in the label “for” binding

Ensure the wpuf- prefix is applied correctly.

-                <label v-if="!is_invisible(field)" :for="'wpuf-' + field.name ? field.name : 'cls'">
+                <label v-if="!is_invisible(field)" :for="'wpuf-' + (field.name ? field.name : 'cls')">
📝 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.

Suggested change
<label v-if="!is_invisible(field)" :for="'wpuf-' + field.name ? field.name : 'cls'">
{{ field.label }} <span v-if="field.required && 'yes' === field.required" class="required">*</span>
</label>
<label v-if="!is_invisible(field)" :for="'wpuf-' + (field.name ? field.name : 'cls')">
{{ field.label }} <span v-if="field.required && 'yes' === field.required" class="required">*</span>
</label>
🤖 Prompt for AI Agents
In admin/form-builder/assets/js/components/builder-stage/template.php around
lines 24 to 26, the :for binding uses "'wpuf-' + field.name ? field.name :
'cls'" which misapplies the ternary due to operator precedence; change the
expression so the ternary decides the name first and then prefixes it (e.g.
field.name ? 'wpuf-'+field.name : 'wpuf-cls') or parenthesize the concatenation
('wpuf-' + (field.name ? field.name : 'cls')) to ensure the wpuf- prefix is
always applied correctly.

Comment on lines +131 to 134
<span v-if="field.show_icon === 'yes' && field.field_icon && field.icon_position === 'right_label'"
class="wpuf-field-label-icon wpuf-inline-flex wpuf-items-center wpuf-ml-2">
<i :class="[field.field_icon, 'wpuf-field-icon']"></i>
</span>
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

A11y: hide right label icon from assistive tech

Same fix here.

-<i :class="[field.field_icon, 'wpuf-field-icon']"></i>
+<i aria-hidden="true" :class="[field.field_icon, 'wpuf-field-icon']"></i>
📝 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.

Suggested change
<span v-if="field.show_icon === 'yes' && field.field_icon && field.icon_position === 'right_label'"
class="wpuf-field-label-icon wpuf-inline-flex wpuf-items-center wpuf-ml-2">
<i :class="[field.field_icon, 'wpuf-field-icon']"></i>
</span>
<span v-if="field.show_icon === 'yes' && field.field_icon && field.icon_position === 'right_label'"
class="wpuf-field-label-icon wpuf-inline-flex wpuf-items-center wpuf-ml-2">
<i aria-hidden="true" :class="[field.field_icon, 'wpuf-field-icon']"></i>
</span>
🤖 Prompt for AI Agents
In assets/js-templates/form-components.php around lines 131 to 134, the right
label icon is currently exposed to assistive technology; update the icon element
so it is ignored by screen readers by adding an accessibility attribute (e.g.,
aria-hidden="true" on the <i> element or role="presentation" with tabindex="-1")
to hide it from AT, and if the icon conveys information ensure an appropriate
accessible text/aria-label is present on the label instead.

Comment on lines +294 to +361
<script type="text/x-template" id="tmpl-wpuf-field-icon_selector">
<div class="panel-field-opt panel-field-opt-icon-selector">
<div class="wpuf-flex">
<label v-if="option_field.title" class="!wpuf-mb-0">
{{ option_field.title }} <help-text v-if="option_field.help_text" :text="option_field.help_text"></help-text>
</label>
</div>

<div class="option-fields-section wpuf-relative">
<div
@click.stop="togglePicker"
class="wpuf-w-full wpuf-min-w-full !wpuf-py-[10px] !wpuf-px-[14px] wpuf-text-gray-700 wpuf-font-medium !wpuf-shadow-sm wpuf-border !wpuf-border-gray-300 !wpuf-rounded-[6px] hover:!wpuf-text-gray-700 wpuf-flex wpuf-justify-between wpuf-items-center !wpuf-text-base wpuf-cursor-pointer"
>
<div class="wpuf-flex wpuf-items-center wpuf-gap-2">
<i v-if="value" :class="value" class="wpuf-text-gray-600"></i>
<span>{{ selectedIconDisplay }}</span>
</div>
<div class="wpuf-flex wpuf-items-center wpuf-gap-1">
<i v-if="value" @click.stop="clearIcon" class="fa fa-times wpuf-text-gray-500 hover:wpuf-text-red-500 wpuf-cursor-pointer wpuf-p-1"></i>
<i :class="showIconPicker ? 'fa-angle-up' : 'fa-angle-down'" class="fa wpuf-text-base"></i>
</div>
</div>

<div
v-if="showIconPicker"
@click.stop
class="wpuf-absolute wpuf-bg-white wpuf-border wpuf-border-gray-300 wpuf-rounded-lg wpuf-w-full wpuf-z-50 wpuf-mt-1 wpuf-shadow-lg wpuf-right-0"
style="max-height: 300px; min-width: 320px; max-width: 400px;"
>
<!-- Search -->
<div class="wpuf-p-3 wpuf-border-b wpuf-border-gray-200">
<input
v-model="searchTerm"
type="text"
placeholder="Search icons... (e.g., user, email, home)"
class="wpuf-w-full !wpuf-px-4 !wpuf-py-1.5 wpuf-border wpuf-border-gray-300 wpuf-rounded wpuf-text-sm wpuf-text-gray-900 placeholder:wpuf-text-gray-400 wpuf-shadow focus:!wpuf-shadow-none"
>
<div class="wpuf-text-xs wpuf-text-gray-500 wpuf-mt-1">
{{ filteredIcons.length }} icons {{ searchTerm ? 'found' : 'available' }}
</div>
</div>

<!-- Icons Grid -->
<div class="wpuf-icon-grid-container" style="max-height: 210px; overflow-y: auto; padding: 10px;">
<!-- Icons Grid -->
<div v-if="filteredIcons.length > 0" class="wpuf-icon-grid" style="display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px;">
<div
v-for="icon in filteredIcons"
:key="icon.class"
@click="selectIcon(icon.class)"
:class="['wpuf-icon-grid-item', { 'selected': value === icon.class }]"
:title="icon.name + ' - ' + icon.keywords"
style="padding: 10px 5px; text-align: center; border: 1px solid #e0e0e0; border-radius: 4px; cursor: pointer; transition: all 0.2s; min-height: 60px; display: flex; flex-direction: column; align-items: center; justify-content: center;"
>
<i :class="icon.class" style="font-size: 18px; margin-bottom: 4px; color: #555;"></i>
<div style="font-size: 10px; color: #666; line-height: 1.2; word-break: break-word; max-width: 100%;">{{ icon.name }}</div>
</div>
</div>

<!-- No Results -->
<div v-else class="wpuf-text-center wpuf-py-8 wpuf-text-gray-500">
<div style="font-size: 16px; margin-bottom: 8px;">🔍 No icons found</div>
<div style="font-size: 12px;">Try searching with different keywords like "user", "email", "home"</div>
</div>
</div>
</div>
</div>
</div></script>
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Localize user-facing strings

Hardcoded English strings (“Search icons…”, “No icons found”, “Try searching…”, “…icons found/available”) bypass translation.

Minimal patch for static literals:

- placeholder="Search icons... (e.g., user, email, home)"
+ :placeholder="'<?php echo esc_attr__('Search icons... (e.g., user, email, home)', 'wp-user-frontend'); ?>'"

- <div style="font-size: 16px; margin-bottom: 8px;">🔍 No icons found</div>
+ <div style="font-size: 16px; margin-bottom: 8px;">🔍 <?php echo esc_html__('No icons found', 'wp-user-frontend'); ?></div>

- <div style="font-size: 12px;">Try searching with different keywords like "user", "email", "home"</div>
+ <div style="font-size: 12px;"><?php echo esc_html__('Try searching with different keywords like "user", "email", "home"', 'wp-user-frontend'); ?></div>

For the dynamic “{{ filteredIcons.length }} icons …”, consider exposing a localized singular/plural suffix via a localized JS object.

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

Suggested change
<script type="text/x-template" id="tmpl-wpuf-field-icon_selector">
<div class="panel-field-opt panel-field-opt-icon-selector">
<div class="wpuf-flex">
<label v-if="option_field.title" class="!wpuf-mb-0">
{{ option_field.title }} <help-text v-if="option_field.help_text" :text="option_field.help_text"></help-text>
</label>
</div>
<div class="option-fields-section wpuf-relative">
<div
@click.stop="togglePicker"
class="wpuf-w-full wpuf-min-w-full !wpuf-py-[10px] !wpuf-px-[14px] wpuf-text-gray-700 wpuf-font-medium !wpuf-shadow-sm wpuf-border !wpuf-border-gray-300 !wpuf-rounded-[6px] hover:!wpuf-text-gray-700 wpuf-flex wpuf-justify-between wpuf-items-center !wpuf-text-base wpuf-cursor-pointer"
>
<div class="wpuf-flex wpuf-items-center wpuf-gap-2">
<i v-if="value" :class="value" class="wpuf-text-gray-600"></i>
<span>{{ selectedIconDisplay }}</span>
</div>
<div class="wpuf-flex wpuf-items-center wpuf-gap-1">
<i v-if="value" @click.stop="clearIcon" class="fa fa-times wpuf-text-gray-500 hover:wpuf-text-red-500 wpuf-cursor-pointer wpuf-p-1"></i>
<i :class="showIconPicker ? 'fa-angle-up' : 'fa-angle-down'" class="fa wpuf-text-base"></i>
</div>
</div>
<div
v-if="showIconPicker"
@click.stop
class="wpuf-absolute wpuf-bg-white wpuf-border wpuf-border-gray-300 wpuf-rounded-lg wpuf-w-full wpuf-z-50 wpuf-mt-1 wpuf-shadow-lg wpuf-right-0"
style="max-height: 300px; min-width: 320px; max-width: 400px;"
>
<!-- Search -->
<div class="wpuf-p-3 wpuf-border-b wpuf-border-gray-200">
<input
v-model="searchTerm"
type="text"
placeholder="Search icons... (e.g., user, email, home)"
class="wpuf-w-full !wpuf-px-4 !wpuf-py-1.5 wpuf-border wpuf-border-gray-300 wpuf-rounded wpuf-text-sm wpuf-text-gray-900 placeholder:wpuf-text-gray-400 wpuf-shadow focus:!wpuf-shadow-none"
>
<div class="wpuf-text-xs wpuf-text-gray-500 wpuf-mt-1">
{{ filteredIcons.length }} icons {{ searchTerm ? 'found' : 'available' }}
</div>
</div>
<!-- Icons Grid -->
<div class="wpuf-icon-grid-container" style="max-height: 210px; overflow-y: auto; padding: 10px;">
<!-- Icons Grid -->
<div v-if="filteredIcons.length > 0" class="wpuf-icon-grid" style="display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px;">
<div
v-for="icon in filteredIcons"
:key="icon.class"
@click="selectIcon(icon.class)"
:class="['wpuf-icon-grid-item', { 'selected': value === icon.class }]"
:title="icon.name + ' - ' + icon.keywords"
style="padding: 10px 5px; text-align: center; border: 1px solid #e0e0e0; border-radius: 4px; cursor: pointer; transition: all 0.2s; min-height: 60px; display: flex; flex-direction: column; align-items: center; justify-content: center;"
>
<i :class="icon.class" style="font-size: 18px; margin-bottom: 4px; color: #555;"></i>
<div style="font-size: 10px; color: #666; line-height: 1.2; word-break: break-word; max-width: 100%;">{{ icon.name }}</div>
</div>
</div>
<!-- No Results -->
<div v-else class="wpuf-text-center wpuf-py-8 wpuf-text-gray-500">
<div style="font-size: 16px; margin-bottom: 8px;">🔍 No icons found</div>
<div style="font-size: 12px;">Try searching with different keywords like "user", "email", "home"</div>
</div>
</div>
</div>
</div>
</div></script>
<script type="text/x-template" id="tmpl-wpuf-field-icon_selector">
<div class="panel-field-opt panel-field-opt-icon-selector">
<div class="wpuf-flex">
<label v-if="option_field.title" class="!wpuf-mb-0">
{{ option_field.title }} <help-text v-if="option_field.help_text" :text="option_field.help_text"></help-text>
</label>
</div>
<div class="option-fields-section wpuf-relative">
<div
@click.stop="togglePicker"
class="wpuf-w-full wpuf-min-w-full !wpuf-py-[10px] !wpuf-px-[14px] wpuf-text-gray-700 wpuf-font-medium !wpuf-shadow-sm wpuf-border !wpuf-border-gray-300 !wpuf-rounded-[6px] hover:!wpuf-text-gray-700 wpuf-flex wpuf-justify-between wpuf-items-center !wpuf-text-base wpuf-cursor-pointer"
>
<div class="wpuf-flex wpuf-items-center wpuf-gap-2">
<i v-if="value" :class="value" class="wpuf-text-gray-600"></i>
<span>{{ selectedIconDisplay }}</span>
</div>
<div class="wpuf-flex wpuf-items-center wpuf-gap-1">
<i v-if="value" @click.stop="clearIcon" class="fa fa-times wpuf-text-gray-500 hover:wpuf-text-red-500 wpuf-cursor-pointer wpuf-p-1"></i>
<i :class="showIconPicker ? 'fa-angle-up' : 'fa-angle-down'" class="fa wpuf-text-base"></i>
</div>
</div>
<div
v-if="showIconPicker"
@click.stop
class="wpuf-absolute wpuf-bg-white wpuf-border wpuf-border-gray-300 wpuf-rounded-lg wpuf-w-full wpuf-z-50 wpuf-mt-1 wpuf-shadow-lg wpuf-right-0"
style="max-height: 300px; min-width: 320px; max-width: 400px;"
>
<!-- Search -->
<div class="wpuf-p-3 wpuf-border-b wpuf-border-gray-200">
<input
v-model="searchTerm"
type="text"
:placeholder="'<?php echo esc_attr__('Search icons... (e.g., user, email, home)', 'wp-user-frontend'); ?>'"
class="wpuf-w-full !wpuf-px-4 !wpuf-py-1.5 wpuf-border wpuf-border-gray-300 wpuf-rounded wpuf-text-sm wpuf-text-gray-900 placeholder:wpuf-text-gray-400 wpuf-shadow focus:!wpuf-shadow-none"
>
<div class="wpuf-text-xs wpuf-text-gray-500 wpuf-mt-1">
{{ filteredIcons.length }} icons {{ searchTerm ? 'found' : 'available' }}
</div>
</div>
<!-- Icons Grid -->
<div class="wpuf-icon-grid-container" style="max-height: 210px; overflow-y: auto; padding: 10px;">
<!-- Icons Grid -->
<div v-if="filteredIcons.length > 0" class="wpuf-icon-grid" style="display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px;">
<div
v-for="icon in filteredIcons"
:key="icon.class"
@click="selectIcon(icon.class)"
:class="['wpuf-icon-grid-item', { 'selected': value === icon.class }]"
:title="icon.name + ' - ' + icon.keywords"
style="padding: 10px 5px; text-align: center; border: 1px solid #e0e0e0; border-radius: 4px; cursor: pointer; transition: all 0.2s; min-height: 60px; display: flex; flex-direction: column; align-items: center; justify-content: center;"
>
<i :class="icon.class" style="font-size: 18px; margin-bottom: 4px; color: #555;"></i>
<div style="font-size: 10px; color: #666; line-height: 1.2; word-break: break-word; max-width: 100%;">{{ icon.name }}</div>
</div>
</div>
<!-- No Results -->
<div v-else class="wpuf-text-center wpuf-py-8 wpuf-text-gray-500">
<div style="font-size: 16px; margin-bottom: 8px;">🔍 <?php echo esc_html__('No icons found', 'wp-user-frontend'); ?></div>
<div style="font-size: 12px;"><?php echo esc_html__('Try searching with different keywords like "user", "email", "home"', 'wp-user-frontend'); ?></div>
</div>
</div>
</div>
</div>
</div></script>

Comment on lines +188 to +197
// Initialize icon properties for new fields to ensure Vue reactivity
if (!payload.field.hasOwnProperty('show_icon')) {
payload.field.show_icon = 'no';
}
if (!payload.field.hasOwnProperty('field_icon')) {
payload.field.field_icon = '';
}
if (!payload.field.hasOwnProperty('icon_position')) {
payload.field.icon_position = 'left_label';
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Good defaulting, but ensure reactivity for existing/nested fields

Initializing on add is fine. However, fields loaded from the server (or nested column/repeat inserts and clones) may lack these keys, and later writes won’t be reactive in Vue 2 unless the properties exist up front. Add a normalization pass in set_form_fields and call it in nested add/clone paths.

Apply this diff to normalize incoming fields:

@@
-            set_form_fields: function (state, form_fields) {
-                Vue.set(state, 'form_fields', form_fields);
-            },
+            set_form_fields: function (state, form_fields) {
+                form_fields.forEach(ensureIconDefaultsRecursively);
+                Vue.set(state, 'form_fields', form_fields);
+            },

Also normalize before inserting nested fields and after cloning:

@@
             add_column_inner_field_element: function (state, payload) {
                 var columnFieldIndex = state.form_fields.findIndex(field => field.id === payload.toWhichColumnField);
 
                 if (state.form_fields[columnFieldIndex].inner_fields[payload.toWhichColumn] === undefined) {
                     state.form_fields[columnFieldIndex].inner_fields[payload.toWhichColumn] = [];
                 } else {
+                    ensureIconDefaults(payload.field);
                     state.form_fields[columnFieldIndex].inner_fields[payload.toWhichColumn].splice( payload.toIndex, 0, payload.field );
                 }
             },
@@
             add_repeat_inner_field_element: function (state, payload) {
                 var repeatFieldIndex = state.form_fields.findIndex(field => field.id === payload.toWhichRepeatField);
                 if (repeatFieldIndex === -1) return;
                 if (!state.form_fields[repeatFieldIndex].inner_fields) {
                     Vue.set(state.form_fields[repeatFieldIndex], 'inner_fields', []);
                 }
+                ensureIconDefaults(payload.field);
                 state.form_fields[repeatFieldIndex].inner_fields.splice(payload.toIndex, 0, payload.field);
             },
@@
             clone_form_field_element: function (state, payload) {
@@
-                clone.is_new = true;
+                clone.is_new = true;
+                ensureIconDefaultsRecursively(clone);
 
                 state.form_fields.splice(index, 0, clone);
             },

Add these helpers once (top-level in this module):

function ensureIconDefaults(obj) {
    if (!obj) return;
    if (!obj.hasOwnProperty('show_icon')) Vue.set(obj, 'show_icon', 'no');
    if (!obj.hasOwnProperty('field_icon')) Vue.set(obj, 'field_icon', '');
    if (!obj.hasOwnProperty('icon_position')) Vue.set(obj, 'icon_position', 'left_label');
}
function ensureIconDefaultsRecursively(field) {
    ensureIconDefaults(field);
    if (field && field.template === 'column_field' && field.inner_fields) {
        Object.keys(field.inner_fields).forEach(col => (field.inner_fields[col] || []).forEach(ensureIconDefaultsRecursively));
    }
    if (field && field.template === 'repeat_field' && Array.isArray(field.inner_fields)) {
        field.inner_fields.forEach(ensureIconDefaultsRecursively);
    }
}
🤖 Prompt for AI Agents
In assets/js/wpuf-form-builder.js around lines 188 to 197, fields loaded from
the server or added via nested column/repeat inserts and clones may lack
show_icon/field_icon/icon_position keys and assigning them directly won't be
reactive in Vue 2; add two helper functions at the top of this module:
ensureIconDefaults(obj) which uses Vue.set to add missing keys with the same
defaults ('no', '', 'left_label'), and ensureIconDefaultsRecursively(field)
which calls ensureIconDefaults and then walks inner_fields for templates
'column_field' and 'repeat_field' to apply recursively; call
ensureIconDefaultsRecursively in set_form_fields when normalizing incoming
fields and also invoke ensureIconDefaults (or the recursive helper) right before
inserting nested fields and immediately after cloning so all new or loaded
fields have the reactive properties.

@Rubaiyat-E-Mohammad Rubaiyat-E-Mohammad added QA Approved This PR is approved by the QA team and removed bug labels Sep 17, 2025
Copy link
Member

@sapayth sapayth left a comment

Choose a reason for hiding this comment

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

check the comments please

},

methods: {
getAllIcons: function() {
Copy link
Member

Choose a reason for hiding this comment

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

move this to a separate file for better organization

if (newVal === 'yes' && oldVal === 'no') {
if (!this.editing_form_field.field_icon || this.editing_form_field.field_icon === 'fas fa-0') {
// Set a proper default icon based on field type
var defaultIcons = {
Copy link
Member

Choose a reason for hiding this comment

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

move this to a separate file for better organization

wpuf.php Outdated
public function includes() {
require_once __DIR__ . '/wpuf-functions.php';
require_once __DIR__ . '/includes/class-frontend-render-form.php';
require_once __DIR__ . '/includes/class-wpuf-icon-loader.php';
Copy link
Member

Choose a reason for hiding this comment

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

use PSR naming convention and add the file only when needed

@sapayth sapayth added needs: author reply This PR needs author feedback or code changes and removed needs: dev review This PR needs review by a developer labels Sep 23, 2025
Copy link

@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 (6)
admin/form-builder/assets/js/components/field-icon_selector/index.js (6)

6-12: Deduplicate and queue config loads to avoid multiple script injections and callback races.

Concurrent mounts can append several identical <script> tags and drop callbacks. Queue callbacks and guard with a loading flag; also set an id to the script node.

-    // Function to dynamically load icons-config.js
-    function loadIconsConfig(callback) {
-        if (iconsLoaded && iconsConfig) {
-            callback(iconsConfig);
-            return;
-        }
-    ...
-        var script = document.createElement('script');
+    // Function to dynamically load icons-config.js (dedup + queue)
+    var loading = false;
+    var pendingCallbacks = [];
+    function loadIconsConfig(callback) {
+        if (iconsLoaded && iconsConfig) {
+            return callback && callback(iconsConfig);
+        }
+        if (callback) {
+            pendingCallbacks.push(callback);
+        }
+        if (loading) {
+            return;
+        }
+        loading = true;
+        var script = document.createElement('script');
+        script.id = 'wpuf-icons-config';
+        script.async = true;
         script.src = (typeof wpuf_form_builder !== 'undefined' && wpuf_form_builder.asset_url)
             ? wpuf_form_builder.asset_url + 'js/components/field-icon_selector/icons-config.js'
             : '/wp-content/plugins/wp-user-frontend/admin/form-builder/assets/js/components/field-icon_selector/icons-config.js';
 
-        script.onload = function() {
-            iconsLoaded = true;
-            // Store the loaded configuration
-            iconsConfig = {
-                getAllIcons: window.getAllIcons || function() { return []; },
-                defaultIcons: window.defaultIcons || {}
-            };
-            if (callback) callback(iconsConfig);
-        };
+        script.onload = function() {
+            iconsLoaded = true;
+            iconsConfig = {
+                getAllIcons: window.getAllIcons || function() { return []; },
+                defaultIcons: window.defaultIcons || {}
+            };
+            loading = false;
+            var cbs = pendingCallbacks.slice(); pendingCallbacks.length = 0;
+            for (var i = 0; i < cbs.length; i++) { cbs[i](iconsConfig); }
+        };
 
-        script.onerror = function() {
-            console.error('Failed to load icons-config.js');
-            iconsConfig = {
-                getAllIcons: function() { return []; },
-                defaultIcons: {}
-            };
-            if (callback) callback(iconsConfig);
-        };
+        script.onerror = function() {
+            console.error('Failed to load icons-config.js');
+            // Use fallback once and stop retry storms
+            iconsLoaded = true;
+            iconsConfig = {
+                getAllIcons: function() { return []; },
+                defaultIcons: {}
+            };
+            loading = false;
+            var cbs = pendingCallbacks.slice(); pendingCallbacks.length = 0;
+            for (var i = 0; i < cbs.length; i++) { cbs[i](iconsConfig); }
+        };
 
         document.head.appendChild(script);
     }

Also applies to: 13-39


15-18: Hardcoded fallback path will break on custom WP_CONTENT_DIR setups.

Rely on a localized plugin/base URL (e.g., via wp_localize_script) instead of '/wp-content/...'. Otherwise, sites with moved wp-content or different plugin directories will 404.

Please verify on an install with a non-default WP_CONTENT_DIR.


93-103: Guard against missing/array keywords in filter.

icon.keywords.toLowerCase() will throw if keywords is undefined or an array.

-            return this.icons.filter(function(icon) {
-                return icon.name.toLowerCase().indexOf(searchLower) !== -1 ||
-                       icon.keywords.toLowerCase().indexOf(searchLower) !== -1;
-            });
+            return this.icons.filter(function(icon) {
+                var name = (icon.name || '').toLowerCase();
+                var kws = Array.isArray(icon.keywords)
+                    ? icon.keywords.join(' ').toLowerCase()
+                    : ((icon.keywords || '') + '').toLowerCase();
+                return name.indexOf(searchLower) !== -1 || kws.indexOf(searchLower) !== -1;
+            });

109-112: Remove placeholder class check; it’s Font Awesome 5‑specific and brittle.

'fas fa-0' isn’t a valid FA7 class. Just treat empty/falsey as unset (or validate against the loaded icon list).

-            if (newVal === 'yes' && oldVal === 'no') {
-                if (!this.editing_form_field.field_icon || this.editing_form_field.field_icon === 'fas fa-0') {
+            if (newVal === 'yes' && oldVal === 'no') {
+                if (!this.editing_form_field.field_icon) {

48-51: Attach the document click listener only when the picker is open.

Prevents N global listeners (one per component) and reduces unnecessary work.

-    mounted: function() {
-        document.addEventListener('click', this.handleClickOutside);
-    },
+    mounted: function() {},
...
-        togglePicker: function() {
-            this.showIconPicker = !this.showIconPicker;
-        },
+        togglePicker: function() {
+            this.showIconPicker = !this.showIconPicker;
+            if (this.showIconPicker) {
+                document.addEventListener('click', this.handleClickOutside);
+            } else {
+                document.removeEventListener('click', this.handleClickOutside);
+            }
+        },
...
-    beforeDestroy: function() {
-        document.removeEventListener('click', this.handleClickOutside);
-    }
+    beforeDestroy: function() {
+        document.removeEventListener('click', this.handleClickOutside);
+    }

Also applies to: 146-154, 157-159


90-91: Make the fallback label translatable.

Use wp.i18n if available.

-            return 'Select an icon';
+            return (window.wp && wp.i18n && wp.i18n.__)
+                ? wp.i18n.__('Select an icon', 'wp-user-frontend')
+                : 'Select an icon';
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8a70e94 and ae98dd4.

⛔ Files ignored due to path filters (2)
  • assets/js/forms-list.min.js is excluded by !**/*.min.js
  • assets/js/subscriptions.min.js is excluded by !**/*.min.js
📒 Files selected for processing (1)
  • admin/form-builder/assets/js/components/field-icon_selector/index.js (1 hunks)
🔇 Additional comments (1)
admin/form-builder/assets/js/components/field-icon_selector/index.js (1)

1-161: Nice modularization; previous ask addressed.

This is now a dedicated component with clear responsibilities. Good job extracting it.

@arifulhoque7 arifulhoque7 force-pushed the feature/dynamic-field-icons branch from ae98dd4 to 511e0e7 Compare September 23, 2025 08:30
@arifulhoque7 arifulhoque7 added needs: dev review This PR needs review by a developer and removed needs: author reply This PR needs author feedback or code changes labels Sep 23, 2025
@arifulhoque7
Copy link
Contributor Author

done @sapayth vai

Copy link

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

🧹 Nitpick comments (4)
assets/js/wpuf-form-builder-components.js (1)

491-512: Broaden watcher condition so defaults apply on first enable.

If oldVal is undefined and newVal is 'yes', default icon won’t set.

-        if (newVal === 'yes' && oldVal === 'no') {
+        if (newVal === 'yes' && oldVal !== 'yes') {
wpuf.php (1)

159-164: Optional: prefer wp_doing_ajax().

Minor style consistency with core helper.

-        if ( is_admin() || ( defined( 'DOING_AJAX' ) && DOING_AJAX ) ) {
+        if ( is_admin() || wp_doing_ajax() ) {
includes/WPUF_Icon_Loader.php (2)

120-159: Remove unused private method flagged by PHPMD.

format_icon_name() is unused. Drop it to reduce noise.

-    /**
-     * Format icon filename to readable name
-     *
-     * @param string $filename
-     * @return string
-     */
-    private function format_icon_name( $filename ) {
-        // Convert kebab-case to Title Case
-        $name = str_replace( '-', ' ', $filename );
-        $name = ucwords( $name );
-
-        // Handle common abbreviations
-        $replacements = [
-            'Css' => 'CSS',
-            'Html' => 'HTML',
-            'Js' => 'JS',
-            'Php' => 'PHP',
-            'Sql' => 'SQL',
-            'Url' => 'URL',
-            'Wifi' => 'WiFi',
-            'Api' => 'API',
-            'Ui' => 'UI',
-            'Ux' => 'UX',
-            'Db' => 'DB',
-            'Id' => 'ID',
-            'Tv' => 'TV',
-            'Dvd' => 'DVD',
-            'Cd' => 'CD',
-            'Usb' => 'USB',
-            'Gps' => 'GPS',
-            'Fax' => 'FAX',
-            'Pdf' => 'PDF',
-            'Gif' => 'GIF',
-            'Jpg' => 'JPG',
-            'Png' => 'PNG',
-            'Mp3' => 'MP3',
-            'Mp4' => 'MP4',
-            'Avi' => 'AVI'
-        ];
-
-        foreach ( $replacements as $search => $replace ) {
-            $name = str_replace( $search, $replace, $name );
-        }
-
-        return $name;
-    }

6-10: Docblock version tag doesn’t match plugin version.

@SInCE 4.2.0 but plugin header is 4.1.11. Align or bump plugin version.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ae98dd4 and 66e6262.

📒 Files selected for processing (5)
  • admin/form-builder/assets/js/components/field-icon_selector/index.js (1 hunks)
  • assets/js/wpuf-form-builder-components.js (1 hunks)
  • includes/Assets.php (3 hunks)
  • includes/WPUF_Icon_Loader.php (1 hunks)
  • wpuf.php (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • admin/form-builder/assets/js/components/field-icon_selector/index.js
🧰 Additional context used
🧬 Code graph analysis (2)
wpuf.php (1)
includes/WPUF_Icon_Loader.php (2)
  • WPUF_Icon_Loader (10-172)
  • init (166-171)
includes/WPUF_Icon_Loader.php (1)
wpuf.php (1)
  • __construct (74-88)
🪛 PHPMD (2.15.0)
includes/WPUF_Icon_Loader.php

120-159: Avoid unused private methods such as 'format_icon_name'. (undefined)

(UnusedPrivateMethod)

🔇 Additional comments (6)
includes/Assets.php (3)

308-309: LGTM: dependency wired.

form-builder-wpuf-forms depending on wpuf-field-icon-selector-config ensures icon data before usage.


301-305: Confirm icons-config.js exists and is publicly accessible

Repo search returned no match for admin/form-builder/assets/js/components/field-icon_selector/icons-config.js — ensure the file ships with the plugin and is reachable via WPUF_ROOT_URI or update the path.


275-276: Ensure wpuf-field-icon-selector-config is registered before use

icons-config.js exists at admin/form-builder/assets/js/components/field-icon_selector/icons-config.js and wpuf-form-builder-components reads window.getAllIcons / window.defaultIcons (assets/js/wpuf-form-builder-components.js). Confirm the script handle 'wpuf-field-icon-selector-config' is registered/enqueued before registering/enqueuing 'wpuf-form-builder-components' (includes/Assets.php lines 275–276); otherwise the builder will break.

assets/js/wpuf-form-builder-components.js (2)

439-442: LGTM: click-outside handler attaches/cleans correctly.

Also applies to: 537-539


444-449: Verify icons source availability

Icons rely on window.getAllIcons(); ensure icons-config.js (or equivalent) defines window.getAllIcons and is loaded/enqueued before assets/js/wpuf-form-builder-components.js (lines 444–449).

wpuf.php (1)

159-164: Good: lazy-load icon loader only in admin/AJAX.

Addresses prior note to load only when needed.

Comment on lines +476 to +487
filteredIcons: function() {
var self = this;
if (!this.icons.length) return [];

if (!this.searchTerm) return this.icons;

var searchLower = this.searchTerm.toLowerCase();
return this.icons.filter(function(icon) {
return icon.name.toLowerCase().indexOf(searchLower) !== -1 ||
icon.keywords.toLowerCase().indexOf(searchLower) !== -1;
});
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Guard against missing keywords to prevent runtime errors.

filteredIcons assumes icon.keywords is a string. If undefined, this throws.

Apply:

-            return this.icons.filter(function(icon) {
-                return icon.name.toLowerCase().indexOf(searchLower) !== -1 ||
-                       icon.keywords.toLowerCase().indexOf(searchLower) !== -1;
-            });
+            return this.icons.filter(function(icon) {
+                var kw = (icon.keywords || '').toString().toLowerCase();
+                return (icon.name || '').toString().toLowerCase().indexOf(searchLower) !== -1 ||
+                       kw.indexOf(searchLower) !== -1;
+            });
📝 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.

Suggested change
filteredIcons: function() {
var self = this;
if (!this.icons.length) return [];
if (!this.searchTerm) return this.icons;
var searchLower = this.searchTerm.toLowerCase();
return this.icons.filter(function(icon) {
return icon.name.toLowerCase().indexOf(searchLower) !== -1 ||
icon.keywords.toLowerCase().indexOf(searchLower) !== -1;
});
}
filteredIcons: function() {
var self = this;
if (!this.icons.length) return [];
if (!this.searchTerm) return this.icons;
var searchLower = this.searchTerm.toLowerCase();
return this.icons.filter(function(icon) {
var kw = (icon.keywords || '').toString().toLowerCase();
return (icon.name || '').toString().toLowerCase().indexOf(searchLower) !== -1 ||
kw.indexOf(searchLower) !== -1;
});
}
🤖 Prompt for AI Agents
In assets/js/wpuf-form-builder-components.js around lines 476 to 487, the
filteredIcons method calls toLowerCase() on icon.keywords which can be undefined
and cause a runtime error; update the filter to guard against missing or
non-string keywords (and optionally missing name) by coercing them to a safe
string before calling toLowerCase(), e.g. default keyword/name to '' or check
typeof before using toLowerCase(), so the filter never calls methods on
undefined.

Comment on lines +136 to 138
'src' => WPUF_ASSET_URI . '/vendor/font-awesome/css/all.min.css',
'version' => '7.0.1',
],
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

🧩 Analysis chain

Font Awesome v7 classes mismatch with code (broken icons risk).

You switched to FA 7 CSS, but several places still use FA 5 class prefixes (‘fas’, ‘fab’) and deprecated names (‘fa-times’, ‘fa-cog’) from includes/WPUF_Icon_Loader.php and elsewhere. This will cause icons not to render.

Apply this update in WPUF_Icon_Loader to align with FA 7:

-['class' => 'fas fa-home',      'name' => 'Home',       'filename' => 'home',       'style' => 'solid'],
-['class' => 'fas fa-user',      'name' => 'User',       'filename' => 'user',       'style' => 'solid'],
-['class' => 'fas fa-envelope',  'name' => 'Envelope',   'filename' => 'envelope',   'style' => 'solid'],
-['class' => 'fas fa-phone',     'name' => 'Phone',      'filename' => 'phone',      'style' => 'solid'],
-['class' => 'fas fa-calendar',  'name' => 'Calendar',   'filename' => 'calendar',   'style' => 'solid'],
-['class' => 'fas fa-image',     'name' => 'Image',      'filename' => 'image',      'style' => 'solid'],
-['class' => 'fas fa-file',      'name' => 'File',       'filename' => 'file',       'style' => 'solid'],
-['class' => 'fas fa-star',      'name' => 'Star',       'filename' => 'star',       'style' => 'solid'],
-['class' => 'fas fa-heart',     'name' => 'Heart',      'filename' => 'heart',      'style' => 'solid'],
-['class' => 'fas fa-search',    'name' => 'Search',     'filename' => 'search',     'style' => 'solid'],
-['class' => 'fas fa-plus',      'name' => 'Plus',       'filename' => 'plus',       'style' => 'solid'],
-['class' => 'fas fa-minus',     'name' => 'Minus',      'filename' => 'minus',      'style' => 'solid'],
-['class' => 'fas fa-edit',      'name' => 'Edit',       'filename' => 'edit',       'style' => 'solid'],
-['class' => 'fas fa-trash',     'name' => 'Trash',      'filename' => 'trash',      'style' => 'solid'],
-['class' => 'fas fa-download',  'name' => 'Download',   'filename' => 'download',   'style' => 'solid'],
-['class' => 'fas fa-upload',    'name' => 'Upload',     'filename' => 'upload',     'style' => 'solid'],
-['class' => 'fas fa-link',      'name' => 'Link',       'filename' => 'link',       'style' => 'solid'],
-['class' => 'fas fa-lock',      'name' => 'Lock',       'filename' => 'lock',       'style' => 'solid'],
-['class' => 'fas fa-unlock',    'name' => 'Unlock',     'filename' => 'unlock',     'style' => 'solid'],
-['class' => 'fas fa-cog',       'name' => 'Settings',   'filename' => 'cog',        'style' => 'solid'],
-['class' => 'fas fa-check',     'name' => 'Check',      'filename' => 'check',      'style' => 'solid'],
-['class' => 'fas fa-times',     'name' => 'Times',      'filename' => 'times',      'style' => 'solid'],
-['class' => 'fas fa-arrow-up',  'name' => 'Arrow Up',   'filename' => 'arrow-up',   'style' => 'solid'],
-['class' => 'fas fa-arrow-down','name' => 'Arrow Down', 'filename' => 'arrow-down', 'style' => 'solid'],
-['class' => 'fas fa-arrow-left','name' => 'Arrow Left', 'filename' => 'arrow-left', 'style' => 'solid'],
-['class' => 'fas fa-arrow-right','name' => 'Arrow Right','filename' => 'arrow-right','style' => 'solid'],
-['class' => 'fab fa-facebook',  'name' => 'Facebook',   'filename' => 'facebook',   'style' => 'brands'],
-['class' => 'fab fa-twitter',   'name' => 'Twitter',    'filename' => 'twitter',    'style' => 'brands'],
-['class' => 'fab fa-instagram', 'name' => 'Instagram',  'filename' => 'instagram',  'style' => 'brands'],
-['class' => 'fab fa-linkedin',  'name' => 'LinkedIn',   'filename' => 'linkedin',   'style' => 'brands'],
+['class' => 'fa-solid fa-home',      'name' => 'Home',       'filename' => 'home',       'style' => 'solid'],
+['class' => 'fa-solid fa-user',      'name' => 'User',       'filename' => 'user',       'style' => 'solid'],
+['class' => 'fa-solid fa-envelope',  'name' => 'Envelope',   'filename' => 'envelope',   'style' => 'solid'],
+['class' => 'fa-solid fa-phone',     'name' => 'Phone',      'filename' => 'phone',      'style' => 'solid'],
+['class' => 'fa-solid fa-calendar',  'name' => 'Calendar',   'filename' => 'calendar',   'style' => 'solid'],
+['class' => 'fa-solid fa-image',     'name' => 'Image',      'filename' => 'image',      'style' => 'solid'],
+['class' => 'fa-solid fa-file',      'name' => 'File',       'filename' => 'file',       'style' => 'solid'],
+['class' => 'fa-solid fa-star',      'name' => 'Star',       'filename' => 'star',       'style' => 'solid'],
+['class' => 'fa-solid fa-heart',     'name' => 'Heart',      'filename' => 'heart',      'style' => 'solid'],
+['class' => 'fa-solid fa-magnifying-glass', 'name' => 'Search', 'filename' => 'magnifying-glass', 'style' => 'solid'],
+['class' => 'fa-solid fa-plus',      'name' => 'Plus',       'filename' => 'plus',       'style' => 'solid'],
+['class' => 'fa-solid fa-minus',     'name' => 'Minus',      'filename' => 'minus',      'style' => 'solid'],
+['class' => 'fa-solid fa-pen-to-square', 'name' => 'Edit',   'filename' => 'pen-to-square', 'style' => 'solid'],
+['class' => 'fa-solid fa-trash',     'name' => 'Trash',      'filename' => 'trash',      'style' => 'solid'],
+['class' => 'fa-solid fa-download',  'name' => 'Download',   'filename' => 'download',   'style' => 'solid'],
+['class' => 'fa-solid fa-upload',    'name' => 'Upload',     'filename' => 'upload',     'style' => 'solid'],
+['class' => 'fa-solid fa-link',      'name' => 'Link',       'filename' => 'link',       'style' => 'solid'],
+['class' => 'fa-solid fa-lock',      'name' => 'Lock',       'filename' => 'lock',       'style' => 'solid'],
+['class' => 'fa-solid fa-unlock',    'name' => 'Unlock',     'filename' => 'unlock',     'style' => 'solid'],
+['class' => 'fa-solid fa-gear',      'name' => 'Settings',   'filename' => 'gear',       'style' => 'solid'],
+['class' => 'fa-solid fa-check',     'name' => 'Check',      'filename' => 'check',      'style' => 'solid'],
+['class' => 'fa-solid fa-xmark',     'name' => 'X Mark',     'filename' => 'xmark',      'style' => 'solid'],
+['class' => 'fa-solid fa-arrow-up',  'name' => 'Arrow Up',   'filename' => 'arrow-up',   'style' => 'solid'],
+['class' => 'fa-solid fa-arrow-down','name' => 'Arrow Down', 'filename' => 'arrow-down', 'style' => 'solid'],
+['class' => 'fa-solid fa-arrow-left','name' => 'Arrow Left', 'filename' => 'arrow-left', 'style' => 'solid'],
+['class' => 'fa-solid fa-arrow-right','name' => 'Arrow Right','filename' => 'arrow-right','style' => 'solid'],
+['class' => 'fa-brands fa-facebook',  'name' => 'Facebook',   'filename' => 'facebook',   'style' => 'brands'],
+['class' => 'fa-brands fa-twitter',   'name' => 'Twitter',    'filename' => 'twitter',    'style' => 'brands'],
+['class' => 'fa-brands fa-instagram', 'name' => 'Instagram',  'filename' => 'instagram',  'style' => 'brands'],
+['class' => 'fa-brands fa-linkedin',  'name' => 'LinkedIn',   'filename' => 'linkedin',   'style' => 'brands'],

Also verify FA webfonts are present under assets/vendor/font-awesome/webfonts, or icons won’t render.


🏁 Script executed:

#!/bin/bash
# 1) Check the icon loader still uses any FA5 prefixes
rg -n -C1 -g '!**/node_modules/**' -e '\bf(a|as|ab|ar)b?\s' includes/WPUF_Icon_Loader.php

# 2) Confirm FA webfonts exist alongside all.min.css
fd -a 'all.min.css' | sed 's/\/css\/all.min.css//g' | while read base; do ls -la "$base/webfonts" || true; done

# 3) Optionally verify if any code still uses 'fas ' or 'fab ' classes
rg -n -C1 -e '\bfas\s| \bfab\s' -g '!**/node_modules/**'

Length of output: 3888


Update WPUF_Icon_Loader to Font Awesome 7 class names (fa-solid / fa-brands)

includes/WPUF_Icon_Loader.php (lines 80–110) still uses FA5 prefixes ('fas'/'fab') and deprecated names — replace with FA7 equivalents below. FA webfonts were found under assets/vendor/font-awesome/webfonts.

-['class' => 'fas fa-home',      'name' => 'Home',       'filename' => 'home',       'style' => 'solid'],
-['class' => 'fas fa-user',      'name' => 'User',       'filename' => 'user',       'style' => 'solid'],
-['class' => 'fas fa-envelope',  'name' => 'Envelope',   'filename' => 'envelope',   'style' => 'solid'],
-['class' => 'fas fa-phone',     'name' => 'Phone',      'filename' => 'phone',      'style' => 'solid'],
-['class' => 'fas fa-calendar',  'name' => 'Calendar',   'filename' => 'calendar',   'style' => 'solid'],
-['class' => 'fas fa-image',     'name' => 'Image',      'filename' => 'image',      'style' => 'solid'],
-['class' => 'fas fa-file',      'name' => 'File',       'filename' => 'file',       'style' => 'solid'],
-['class' => 'fas fa-star',      'name' => 'Star',       'filename' => 'star',       'style' => 'solid'],
-['class' => 'fas fa-heart',     'name' => 'Heart',      'filename' => 'heart',      'style' => 'solid'],
-['class' => 'fas fa-search',    'name' => 'Search',     'filename' => 'search',     'style' => 'solid'],
-['class' => 'fas fa-plus',      'name' => 'Plus',       'filename' => 'plus',       'style' => 'solid'],
-['class' => 'fas fa-minus',     'name' => 'Minus',      'filename' => 'minus',      'style' => 'solid'],
-['class' => 'fas fa-edit',      'name' => 'Edit',       'filename' => 'edit',       'style' => 'solid'],
-['class' => 'fas fa-trash',     'name' => 'Trash',      'filename' => 'trash',      'style' => 'solid'],
-['class' => 'fas fa-download',  'name' => 'Download',   'filename' => 'download',   'style' => 'solid'],
-['class' => 'fas fa-upload',    'name' => 'Upload',     'filename' => 'upload',     'style' => 'solid'],
-['class' => 'fas fa-link',      'name' => 'Link',       'filename' => 'link',       'style' => 'solid'],
-['class' => 'fas fa-lock',      'name' => 'Lock',       'filename' => 'lock',       'style' => 'solid'],
-['class' => 'fas fa-unlock',    'name' => 'Unlock',     'filename' => 'unlock',     'style' => 'solid'],
-['class' => 'fas fa-cog',       'name' => 'Settings',   'filename' => 'cog',        'style' => 'solid'],
-['class' => 'fas fa-check',     'name' => 'Check',      'filename' => 'check',      'style' => 'solid'],
-['class' => 'fas fa-times',     'name' => 'Times',      'filename' => 'times',      'style' => 'solid'],
-['class' => 'fas fa-arrow-up',  'name' => 'Arrow Up',   'filename' => 'arrow-up',   'style' => 'solid'],
-['class' => 'fas fa-arrow-down','name' => 'Arrow Down', 'filename' => 'arrow-down', 'style' => 'solid'],
-['class' => 'fas fa-arrow-left','name' => 'Arrow Left', 'filename' => 'arrow-left', 'style' => 'solid'],
-['class' => 'fas fa-arrow-right','name' => 'Arrow Right','filename' => 'arrow-right','style' => 'solid'],
-['class' => 'fab fa-facebook',  'name' => 'Facebook',   'filename' => 'facebook',   'style' => 'brands'],
-['class' => 'fab fa-twitter',   'name' => 'Twitter',    'filename' => 'twitter',    'style' => 'brands'],
-['class' => 'fab fa-instagram', 'name' => 'Instagram',  'filename' => 'instagram',  'style' => 'brands'],
-['class' => 'fab fa-linkedin',  'name' => 'LinkedIn',   'filename' => 'linkedin',   'style' => 'brands'],
+['class' => 'fa-solid fa-home',      'name' => 'Home',       'filename' => 'home',       'style' => 'solid'],
+['class' => 'fa-solid fa-user',      'name' => 'User',       'filename' => 'user',       'style' => 'solid'],
+['class' => 'fa-solid fa-envelope',  'name' => 'Envelope',   'filename' => 'envelope',   'style' => 'solid'],
+['class' => 'fa-solid fa-phone',     'name' => 'Phone',      'filename' => 'phone',      'style' => 'solid'],
+['class' => 'fa-solid fa-calendar',  'name' => 'Calendar',   'filename' => 'calendar',   'style' => 'solid'],
+['class' => 'fa-solid fa-image',     'name' => 'Image',      'filename' => 'image',      'style' => 'solid'],
+['class' => 'fa-solid fa-file',      'name' => 'File',       'filename' => 'file',       'style' => 'solid'],
+['class' => 'fa-solid fa-star',      'name' => 'Star',       'filename' => 'star',       'style' => 'solid'],
+['class' => 'fa-solid fa-heart',     'name' => 'Heart',      'filename' => 'heart',      'style' => 'solid'],
+['class' => 'fa-solid fa-magnifying-glass', 'name' => 'Search', 'filename' => 'magnifying-glass', 'style' => 'solid'],
+['class' => 'fa-solid fa-plus',      'name' => 'Plus',       'filename' => 'plus',       'style' => 'solid'],
+['class' => 'fa-solid fa-minus',     'name' => 'Minus',      'filename' => 'minus',      'style' => 'solid'],
+['class' => 'fa-solid fa-pen-to-square', 'name' => 'Edit',   'filename' => 'pen-to-square', 'style' => 'solid'],
+['class' => 'fa-solid fa-trash',     'name' => 'Trash',      'filename' => 'trash',      'style' => 'solid'],
+['class' => 'fa-solid fa-download',  'name' => 'Download',   'filename' => 'download',   'style' => 'solid'],
+['class' => 'fa-solid fa-upload',    'name' => 'Upload',     'filename' => 'upload',     'style' => 'solid'],
+['class' => 'fa-solid fa-link',      'name' => 'Link',       'filename' => 'link',       'style' => 'solid'],
+['class' => 'fa-solid fa-lock',      'name' => 'Lock',       'filename' => 'lock',       'style' => 'solid'],
+['class' => 'fa-solid fa-unlock',    'name' => 'Unlock',     'filename' => 'unlock',     'style' => 'solid'],
+['class' => 'fa-solid fa-gear',      'name' => 'Settings',   'filename' => 'gear',       'style' => 'solid'],
+['class' => 'fa-solid fa-check',     'name' => 'Check',      'filename' => 'check',      'style' => 'solid'],
+['class' => 'fa-solid fa-xmark',     'name' => 'X Mark',     'filename' => 'xmark',      'style' => 'solid'],
+['class' => 'fa-solid fa-arrow-up',  'name' => 'Arrow Up',   'filename' => 'arrow-up',   'style' => 'solid'],
+['class' => 'fa-solid fa-arrow-down','name' => 'Arrow Down', 'filename' => 'arrow-down', 'style' => 'solid'],
+['class' => 'fa-solid fa-arrow-left','name' => 'Arrow Left', 'filename' => 'arrow-left', 'style' => 'solid'],
+['class' => 'fa-solid fa-arrow-right','name' => 'Arrow Right','filename' => 'arrow-right','style' => 'solid'],
+['class' => 'fa-brands fa-facebook',  'name' => 'Facebook',   'filename' => 'facebook',   'style' => 'brands'],
+['class' => 'fa-brands fa-twitter',   'name' => 'Twitter',    'filename' => 'twitter',    'style' => 'brands'],
+['class' => 'fa-brands fa-instagram', 'name' => 'Instagram',  'filename' => 'instagram',  'style' => 'brands'],
+['class' => 'fa-brands fa-linkedin',  'name' => 'LinkedIn',   'filename' => 'linkedin',   'style' => 'brands'],

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In includes/WPUF_Icon_Loader.php around lines 80–110, the code still maps Font
Awesome 5 class prefixes ('fas'/'fab') and some deprecated icon names; update
mappings to use Font Awesome 7 class prefixes ('fa-solid' for solid icons and
'fa-brands' for brand icons), replace any deprecated icon names with their FA7
equivalents, and ensure any enqueue/asset paths reference the webfonts under
assets/vendor/font-awesome/webfonts (and the CSS under
vendor/font-awesome/css/all.min.css as configured in includes/Assets.php) so
icons render correctly with FA7.

Comment on lines 43 to 55
public function ajax_get_icons() {
// Verify nonce
if ( ! wp_verify_nonce( $_POST['nonce'] ?? '', 'wpuf_form_builder_wpuf_forms' ) ) {
wp_send_json_error( 'Invalid nonce' );
}

$icons = $this->load_all_icons();

wp_send_json_success([
'icons' => $icons,
'total' => count( $icons )
]);
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

🧩 Analysis chain

Verify nonce source used in admin.

Ensure the nonce 'wpuf_form_builder_wpuf_forms' is localized and sent by the client.


🏁 Script executed:

#!/bin/bash
# Check nonce creation/localization and usage
rg -n -C2 -e "wp_create_nonce\(\s*'wpuf_form_builder_wpuf_forms'\s*\)" -g '!**/node_modules/**'
rg -n -C2 -e "nonce[\"']?\s*:\s*.*wpuf_form_builder_wpuf_forms" --type=js
rg -n -C2 -e "action[\"']?\s*:\s*['\"]wpuf_get_font_awesome_icons['\"]" --type=js

Length of output: 148


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "repo tracked files: $(git ls-files | wc -l)"
echo "---- search: exact nonce action ----"
rg --hidden -S --no-ignore -n -C3 "wpuf_form_builder_wpuf_forms" -g '!*node_modules/**' || true

echo "---- search: wp_create_nonce('wpuf_form_builder_wpuf_forms') ----"
rg --hidden -S --no-ignore -n -C3 "wp_create_nonce\s*\(\s*['\"]wpuf_form_builder_wpuf_forms['\"]\s*\)" -g '!*node_modules/**' || true

echo "---- search: wp_localize_script occurrences ----"
rg --hidden -S --no-ignore -n -C3 "wp_localize_script\s*\(" -g '!*node_modules/**' || true

echo "---- search: 'nonce' in JS files ----"
rg --hidden -S --no-ignore -n -C3 "nonce\s*[:=]" --type js -g '!*node_modules/**' || true

echo "---- search: JS AJAX action 'wpuf_get_font_awesome_icons' ----"
rg --hidden -S --no-ignore -n -C3 "action\s*:\s*['\"]wpuf_get_font_awesome_icons['\"]" --type js -g '!*node_modules/**' || true

echo "---- search: ajax_get_icons locations ----"
rg --hidden -S --no-ignore -n -C3 "ajax_get_icons" -g '!*node_modules/**' || true

Length of output: 1213


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Tracked files: $(git ls-files | wc -l)"
echo
echo "=== Searching for exact nonce string ==="
git grep -n -- "wpuf_form_builder_wpuf_forms" || true
echo
echo "=== Searching for wp_create_nonce occurrences ==="
git grep -n -- "wp_create_nonce" || true
echo
echo "=== Searching for wp_localize_script occurrences ==="
git grep -n -- "wp_localize_script" || true
echo
echo "=== Searching for wp_enqueue_script occurrences ==="
git grep -n -- "wp_enqueue_script" || true
echo
echo "=== Searching for ajax_get_icons occurrences ==="
git grep -n -- "ajax_get_icons" || true
echo
echo "=== Searching JS files for 'nonce' and 'wpuf_get_font_awesome_icons' ==="
git grep -n "nonce" -- '*.js' || true
git grep -n "wpuf_get_font_awesome_icons" -- '*.js' || true

Length of output: 323929


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "---- includes/Admin/Forms/Admin_Form_Builder.php (full file) ----"
sed -n '1,400p' includes/Admin/Forms/Admin_Form_Builder.php || true

echo
echo "---- includes/WPUF_Icon_Loader.php (around ajax_get_icons) ----"
sed -n '1,220p' includes/WPUF_Icon_Loader.php || true

echo
echo "---- admin/form-builder/assets/js/form-builder.js (around usage) ----"
sed -n '1440,1500p' admin/form-builder/assets/js/form-builder.js || true

Length of output: 25120


Align nonce used by ajax_get_icons with client-side localization

ajax_get_icons verifies nonce 'wpuf_form_builder_wpuf_forms' but the admin scripts/localization provide wpuf_form_builder.nonce = wp_create_nonce('form-builder-setting-nonce'); either localize wp_create_nonce('wpuf_form_builder_wpuf_forms') and send it from the client, or change ajax_get_icons to verify the existing 'form-builder-setting-nonce'.

Locations:

  • includes/WPUF_Icon_Loader.php — ajax_get_icons (wp_verify_nonce(..., 'wpuf_form_builder_wpuf_forms'))
  • includes/Admin/Forms/Admin_Form_Builder.php — wp_localize_script('wpuf-form-builder-mixins', 'wpuf_form_builder', [ 'nonce' => wp_create_nonce('form-builder-setting-nonce') ])
  • admin/form-builder/assets/js/form-builder.js — uses wpuf_form_builder.nonce when sending AJAX
🤖 Prompt for AI Agents
in includes/WPUF_Icon_Loader.php around lines 43 to 55, ajax_get_icons is
verifying nonce 'wpuf_form_builder_wpuf_forms' while the client sends
wpuf_form_builder.nonce created with 'form-builder-setting-nonce'; update
ajax_get_icons to verify the same nonce name used by the client (use
wp_verify_nonce($_POST['nonce'] ?? '', 'form-builder-setting-nonce')) so
server-side verification matches the localized client nonce, and keep the
existing error path (wp_send_json_error) intact.

Comment on lines 81 to 112
['class' => 'fas fa-home', 'name' => 'Home', 'filename' => 'home', 'style' => 'solid'],
['class' => 'fas fa-user', 'name' => 'User', 'filename' => 'user', 'style' => 'solid'],
['class' => 'fas fa-envelope', 'name' => 'Envelope', 'filename' => 'envelope', 'style' => 'solid'],
['class' => 'fas fa-phone', 'name' => 'Phone', 'filename' => 'phone', 'style' => 'solid'],
['class' => 'fas fa-calendar', 'name' => 'Calendar', 'filename' => 'calendar', 'style' => 'solid'],
['class' => 'fas fa-image', 'name' => 'Image', 'filename' => 'image', 'style' => 'solid'],
['class' => 'fas fa-file', 'name' => 'File', 'filename' => 'file', 'style' => 'solid'],
['class' => 'fas fa-star', 'name' => 'Star', 'filename' => 'star', 'style' => 'solid'],
['class' => 'fas fa-heart', 'name' => 'Heart', 'filename' => 'heart', 'style' => 'solid'],
['class' => 'fas fa-search', 'name' => 'Search', 'filename' => 'search', 'style' => 'solid'],
['class' => 'fas fa-plus', 'name' => 'Plus', 'filename' => 'plus', 'style' => 'solid'],
['class' => 'fas fa-minus', 'name' => 'Minus', 'filename' => 'minus', 'style' => 'solid'],
['class' => 'fas fa-edit', 'name' => 'Edit', 'filename' => 'edit', 'style' => 'solid'],
['class' => 'fas fa-trash', 'name' => 'Trash', 'filename' => 'trash', 'style' => 'solid'],
['class' => 'fas fa-download', 'name' => 'Download', 'filename' => 'download', 'style' => 'solid'],
['class' => 'fas fa-upload', 'name' => 'Upload', 'filename' => 'upload', 'style' => 'solid'],
['class' => 'fas fa-link', 'name' => 'Link', 'filename' => 'link', 'style' => 'solid'],
['class' => 'fas fa-lock', 'name' => 'Lock', 'filename' => 'lock', 'style' => 'solid'],
['class' => 'fas fa-unlock', 'name' => 'Unlock', 'filename' => 'unlock', 'style' => 'solid'],
['class' => 'fas fa-cog', 'name' => 'Settings', 'filename' => 'cog', 'style' => 'solid'],
['class' => 'fas fa-check', 'name' => 'Check', 'filename' => 'check', 'style' => 'solid'],
['class' => 'fas fa-times', 'name' => 'Times', 'filename' => 'times', 'style' => 'solid'],
['class' => 'fas fa-arrow-up', 'name' => 'Arrow Up', 'filename' => 'arrow-up', 'style' => 'solid'],
['class' => 'fas fa-arrow-down', 'name' => 'Arrow Down', 'filename' => 'arrow-down', 'style' => 'solid'],
['class' => 'fas fa-arrow-left', 'name' => 'Arrow Left', 'filename' => 'arrow-left', 'style' => 'solid'],
['class' => 'fas fa-arrow-right', 'name' => 'Arrow Right', 'filename' => 'arrow-right', 'style' => 'solid'],
['class' => 'fab fa-facebook', 'name' => 'Facebook', 'filename' => 'facebook', 'style' => 'brands'],
['class' => 'fab fa-twitter', 'name' => 'Twitter', 'filename' => 'twitter', 'style' => 'brands'],
['class' => 'fab fa-instagram', 'name' => 'Instagram', 'filename' => 'instagram', 'style' => 'brands'],
['class' => 'fab fa-linkedin', 'name' => 'LinkedIn', 'filename' => 'linkedin', 'style' => 'brands'],
];
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Update FA classes/names to Font Awesome 7.

Current list uses FA5 prefixes (‘fas’, ‘fab’) and deprecated icon names; these won’t render with FA7 CSS.

Apply:

-            ['class' => 'fas fa-home', 'name' => 'Home', 'filename' => 'home', 'style' => 'solid'],
-            ['class' => 'fas fa-user', 'name' => 'User', 'filename' => 'user', 'style' => 'solid'],
-            ['class' => 'fas fa-envelope', 'name' => 'Envelope', 'filename' => 'envelope', 'style' => 'solid'],
-            ['class' => 'fas fa-phone', 'name' => 'Phone', 'filename' => 'phone', 'style' => 'solid'],
-            ['class' => 'fas fa-calendar', 'name' => 'Calendar', 'filename' => 'calendar', 'style' => 'solid'],
-            ['class' => 'fas fa-image', 'name' => 'Image', 'filename' => 'image', 'style' => 'solid'],
-            ['class' => 'fas fa-file', 'name' => 'File', 'filename' => 'file', 'style' => 'solid'],
-            ['class' => 'fas fa-star', 'name' => 'Star', 'filename' => 'star', 'style' => 'solid'],
-            ['class' => 'fas fa-heart', 'name' => 'Heart', 'filename' => 'heart', 'style' => 'solid'],
-            ['class' => 'fas fa-search', 'name' => 'Search', 'filename' => 'search', 'style' => 'solid'],
-            ['class' => 'fas fa-plus', 'name' => 'Plus', 'filename' => 'plus', 'style' => 'solid'],
-            ['class' => 'fas fa-minus', 'name' => 'Minus', 'filename' => 'minus', 'style' => 'solid'],
-            ['class' => 'fas fa-edit', 'name' => 'Edit', 'filename' => 'edit', 'style' => 'solid'],
-            ['class' => 'fas fa-trash', 'name' => 'Trash', 'filename' => 'trash', 'style' => 'solid'],
-            ['class' => 'fas fa-download', 'name' => 'Download', 'filename' => 'download', 'style' => 'solid'],
-            ['class' => 'fas fa-upload', 'name' => 'Upload', 'filename' => 'upload', 'style' => 'solid'],
-            ['class' => 'fas fa-link', 'name' => 'Link', 'filename' => 'link', 'style' => 'solid'],
-            ['class' => 'fas fa-lock', 'name' => 'Lock', 'filename' => 'lock', 'style' => 'solid'],
-            ['class' => 'fas fa-unlock', 'name' => 'Unlock', 'filename' => 'unlock', 'style' => 'solid'],
-            ['class' => 'fas fa-cog', 'name' => 'Settings', 'filename' => 'cog', 'style' => 'solid'],
-            ['class' => 'fas fa-check', 'name' => 'Check', 'filename' => 'check', 'style' => 'solid'],
-            ['class' => 'fas fa-times', 'name' => 'Times', 'filename' => 'times', 'style' => 'solid'],
-            ['class' => 'fas fa-arrow-up', 'name' => 'Arrow Up', 'filename' => 'arrow-up', 'style' => 'solid'],
-            ['class' => 'fas fa-arrow-down', 'name' => 'Arrow Down', 'filename' => 'arrow-down', 'style' => 'solid'],
-            ['class' => 'fas fa-arrow-left', 'name' => 'Arrow Left', 'filename' => 'arrow-left', 'style' => 'solid'],
-            ['class' => 'fas fa-arrow-right', 'name' => 'Arrow Right', 'filename' => 'arrow-right', 'style' => 'solid'],
-            ['class' => 'fab fa-facebook', 'name' => 'Facebook', 'filename' => 'facebook', 'style' => 'brands'],
-            ['class' => 'fab fa-twitter', 'name' => 'Twitter', 'filename' => 'twitter', 'style' => 'brands'],
-            ['class' => 'fab fa-instagram', 'name' => 'Instagram', 'filename' => 'instagram', 'style' => 'brands'],
-            ['class' => 'fab fa-linkedin', 'name' => 'LinkedIn', 'filename' => 'linkedin', 'style' => 'brands'],
+            ['class' => 'fa-solid fa-home',              'name' => 'Home',      'filename' => 'home',              'style' => 'solid'],
+            ['class' => 'fa-solid fa-user',              'name' => 'User',      'filename' => 'user',              'style' => 'solid'],
+            ['class' => 'fa-solid fa-envelope',          'name' => 'Envelope',  'filename' => 'envelope',          'style' => 'solid'],
+            ['class' => 'fa-solid fa-phone',             'name' => 'Phone',     'filename' => 'phone',             'style' => 'solid'],
+            ['class' => 'fa-solid fa-calendar',          'name' => 'Calendar',  'filename' => 'calendar',          'style' => 'solid'],
+            ['class' => 'fa-solid fa-image',             'name' => 'Image',     'filename' => 'image',             'style' => 'solid'],
+            ['class' => 'fa-solid fa-file',              'name' => 'File',      'filename' => 'file',              'style' => 'solid'],
+            ['class' => 'fa-solid fa-star',              'name' => 'Star',      'filename' => 'star',              'style' => 'solid'],
+            ['class' => 'fa-solid fa-heart',             'name' => 'Heart',     'filename' => 'heart',             'style' => 'solid'],
+            ['class' => 'fa-solid fa-magnifying-glass',  'name' => 'Search',    'filename' => 'magnifying-glass',  'style' => 'solid'],
+            ['class' => 'fa-solid fa-plus',              'name' => 'Plus',      'filename' => 'plus',              'style' => 'solid'],
+            ['class' => 'fa-solid fa-minus',             'name' => 'Minus',     'filename' => 'minus',             'style' => 'solid'],
+            ['class' => 'fa-solid fa-pen-to-square',     'name' => 'Edit',      'filename' => 'pen-to-square',     'style' => 'solid'],
+            ['class' => 'fa-solid fa-trash',             'name' => 'Trash',     'filename' => 'trash',             'style' => 'solid'],
+            ['class' => 'fa-solid fa-download',          'name' => 'Download',  'filename' => 'download',          'style' => 'solid'],
+            ['class' => 'fa-solid fa-upload',            'name' => 'Upload',    'filename' => 'upload',            'style' => 'solid'],
+            ['class' => 'fa-solid fa-link',              'name' => 'Link',      'filename' => 'link',              'style' => 'solid'],
+            ['class' => 'fa-solid fa-lock',              'name' => 'Lock',      'filename' => 'lock',              'style' => 'solid'],
+            ['class' => 'fa-solid fa-unlock',            'name' => 'Unlock',    'filename' => 'unlock',            'style' => 'solid'],
+            ['class' => 'fa-solid fa-gear',              'name' => 'Settings',  'filename' => 'gear',              'style' => 'solid'],
+            ['class' => 'fa-solid fa-check',             'name' => 'Check',     'filename' => 'check',             'style' => 'solid'],
+            ['class' => 'fa-solid fa-xmark',             'name' => 'X Mark',    'filename' => 'xmark',             'style' => 'solid'],
+            ['class' => 'fa-solid fa-arrow-up',          'name' => 'Arrow Up',  'filename' => 'arrow-up',          'style' => 'solid'],
+            ['class' => 'fa-solid fa-arrow-down',        'name' => 'Arrow Down','filename' => 'arrow-down',        'style' => 'solid'],
+            ['class' => 'fa-solid fa-arrow-left',        'name' => 'Arrow Left','filename' => 'arrow-left',        'style' => 'solid'],
+            ['class' => 'fa-solid fa-arrow-right',       'name' => 'Arrow Right','filename' => 'arrow-right',      'style' => 'solid'],
+            ['class' => 'fa-brands fa-facebook',         'name' => 'Facebook',  'filename' => 'facebook',          'style' => 'brands'],
+            ['class' => 'fa-brands fa-twitter',          'name' => 'Twitter',   'filename' => 'twitter',           'style' => 'brands'],
+            ['class' => 'fa-brands fa-instagram',        'name' => 'Instagram', 'filename' => 'instagram',         'style' => 'brands'],
+            ['class' => 'fa-brands fa-linkedin',         'name' => 'LinkedIn',  'filename' => 'linkedin',          'style' => 'brands'],
📝 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.

Suggested change
['class' => 'fas fa-home', 'name' => 'Home', 'filename' => 'home', 'style' => 'solid'],
['class' => 'fas fa-user', 'name' => 'User', 'filename' => 'user', 'style' => 'solid'],
['class' => 'fas fa-envelope', 'name' => 'Envelope', 'filename' => 'envelope', 'style' => 'solid'],
['class' => 'fas fa-phone', 'name' => 'Phone', 'filename' => 'phone', 'style' => 'solid'],
['class' => 'fas fa-calendar', 'name' => 'Calendar', 'filename' => 'calendar', 'style' => 'solid'],
['class' => 'fas fa-image', 'name' => 'Image', 'filename' => 'image', 'style' => 'solid'],
['class' => 'fas fa-file', 'name' => 'File', 'filename' => 'file', 'style' => 'solid'],
['class' => 'fas fa-star', 'name' => 'Star', 'filename' => 'star', 'style' => 'solid'],
['class' => 'fas fa-heart', 'name' => 'Heart', 'filename' => 'heart', 'style' => 'solid'],
['class' => 'fas fa-search', 'name' => 'Search', 'filename' => 'search', 'style' => 'solid'],
['class' => 'fas fa-plus', 'name' => 'Plus', 'filename' => 'plus', 'style' => 'solid'],
['class' => 'fas fa-minus', 'name' => 'Minus', 'filename' => 'minus', 'style' => 'solid'],
['class' => 'fas fa-edit', 'name' => 'Edit', 'filename' => 'edit', 'style' => 'solid'],
['class' => 'fas fa-trash', 'name' => 'Trash', 'filename' => 'trash', 'style' => 'solid'],
['class' => 'fas fa-download', 'name' => 'Download', 'filename' => 'download', 'style' => 'solid'],
['class' => 'fas fa-upload', 'name' => 'Upload', 'filename' => 'upload', 'style' => 'solid'],
['class' => 'fas fa-link', 'name' => 'Link', 'filename' => 'link', 'style' => 'solid'],
['class' => 'fas fa-lock', 'name' => 'Lock', 'filename' => 'lock', 'style' => 'solid'],
['class' => 'fas fa-unlock', 'name' => 'Unlock', 'filename' => 'unlock', 'style' => 'solid'],
['class' => 'fas fa-cog', 'name' => 'Settings', 'filename' => 'cog', 'style' => 'solid'],
['class' => 'fas fa-check', 'name' => 'Check', 'filename' => 'check', 'style' => 'solid'],
['class' => 'fas fa-times', 'name' => 'Times', 'filename' => 'times', 'style' => 'solid'],
['class' => 'fas fa-arrow-up', 'name' => 'Arrow Up', 'filename' => 'arrow-up', 'style' => 'solid'],
['class' => 'fas fa-arrow-down', 'name' => 'Arrow Down', 'filename' => 'arrow-down', 'style' => 'solid'],
['class' => 'fas fa-arrow-left', 'name' => 'Arrow Left', 'filename' => 'arrow-left', 'style' => 'solid'],
['class' => 'fas fa-arrow-right', 'name' => 'Arrow Right', 'filename' => 'arrow-right', 'style' => 'solid'],
['class' => 'fab fa-facebook', 'name' => 'Facebook', 'filename' => 'facebook', 'style' => 'brands'],
['class' => 'fab fa-twitter', 'name' => 'Twitter', 'filename' => 'twitter', 'style' => 'brands'],
['class' => 'fab fa-instagram', 'name' => 'Instagram', 'filename' => 'instagram', 'style' => 'brands'],
['class' => 'fab fa-linkedin', 'name' => 'LinkedIn', 'filename' => 'linkedin', 'style' => 'brands'],
];
}
['class' => 'fa-solid fa-home', 'name' => 'Home', 'filename' => 'home', 'style' => 'solid'],
['class' => 'fa-solid fa-user', 'name' => 'User', 'filename' => 'user', 'style' => 'solid'],
['class' => 'fa-solid fa-envelope', 'name' => 'Envelope', 'filename' => 'envelope', 'style' => 'solid'],
['class' => 'fa-solid fa-phone', 'name' => 'Phone', 'filename' => 'phone', 'style' => 'solid'],
['class' => 'fa-solid fa-calendar', 'name' => 'Calendar', 'filename' => 'calendar', 'style' => 'solid'],
['class' => 'fa-solid fa-image', 'name' => 'Image', 'filename' => 'image', 'style' => 'solid'],
['class' => 'fa-solid fa-file', 'name' => 'File', 'filename' => 'file', 'style' => 'solid'],
['class' => 'fa-solid fa-star', 'name' => 'Star', 'filename' => 'star', 'style' => 'solid'],
['class' => 'fa-solid fa-heart', 'name' => 'Heart', 'filename' => 'heart', 'style' => 'solid'],
['class' => 'fa-solid fa-magnifying-glass', 'name' => 'Search', 'filename' => 'magnifying-glass', 'style' => 'solid'],
['class' => 'fa-solid fa-plus', 'name' => 'Plus', 'filename' => 'plus', 'style' => 'solid'],
['class' => 'fa-solid fa-minus', 'name' => 'Minus', 'filename' => 'minus', 'style' => 'solid'],
['class' => 'fa-solid fa-pen-to-square', 'name' => 'Edit', 'filename' => 'pen-to-square', 'style' => 'solid'],
['class' => 'fa-solid fa-trash', 'name' => 'Trash', 'filename' => 'trash', 'style' => 'solid'],
['class' => 'fa-solid fa-download', 'name' => 'Download', 'filename' => 'download', 'style' => 'solid'],
['class' => 'fa-solid fa-upload', 'name' => 'Upload', 'filename' => 'upload', 'style' => 'solid'],
['class' => 'fa-solid fa-link', 'name' => 'Link', 'filename' => 'link', 'style' => 'solid'],
['class' => 'fa-solid fa-lock', 'name' => 'Lock', 'filename' => 'lock', 'style' => 'solid'],
['class' => 'fa-solid fa-unlock', 'name' => 'Unlock', 'filename' => 'unlock', 'style' => 'solid'],
['class' => 'fa-solid fa-gear', 'name' => 'Settings', 'filename' => 'gear', 'style' => 'solid'],
['class' => 'fa-solid fa-check', 'name' => 'Check', 'filename' => 'check', 'style' => 'solid'],
['class' => 'fa-solid fa-xmark', 'name' => 'X Mark', 'filename' => 'xmark', 'style' => 'solid'],
['class' => 'fa-solid fa-arrow-up', 'name' => 'Arrow Up', 'filename' => 'arrow-up', 'style' => 'solid'],
['class' => 'fa-solid fa-arrow-down', 'name' => 'Arrow Down','filename' => 'arrow-down', 'style' => 'solid'],
['class' => 'fa-solid fa-arrow-left', 'name' => 'Arrow Left','filename' => 'arrow-left', 'style' => 'solid'],
['class' => 'fa-solid fa-arrow-right', 'name' => 'Arrow Right','filename' => 'arrow-right', 'style' => 'solid'],
['class' => 'fa-brands fa-facebook', 'name' => 'Facebook', 'filename' => 'facebook', 'style' => 'brands'],
['class' => 'fa-brands fa-twitter', 'name' => 'Twitter', 'filename' => 'twitter', 'style' => 'brands'],
['class' => 'fa-brands fa-instagram', 'name' => 'Instagram', 'filename' => 'instagram', 'style' => 'brands'],
['class' => 'fa-brands fa-linkedin', 'name' => 'LinkedIn', 'filename' => 'linkedin', 'style' => 'brands'],
];
}

*/
private function get_common_icons() {
return [
['class' => 'fas fa-home', 'name' => 'Home', 'filename' => 'home', 'style' => 'solid'],
Copy link
Member

Choose a reason for hiding this comment

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

can we use the same admin/form-builder/assets/js/components/field-icon_selector/icons-config.js file? or create a json file to use in both .js and .php?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done @sapayth vai

@sapayth sapayth removed the needs: dev review This PR needs review by a developer label Oct 13, 2025
@sapayth sapayth added the needs: author reply This PR needs author feedback or code changes label Oct 13, 2025
@arifulhoque7 arifulhoque7 added needs: dev review This PR needs review by a developer and removed needs: author reply This PR needs author feedback or code changes labels Oct 13, 2025
Copy link

@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

♻️ Duplicate comments (2)
assets/js/wpuf-form-builder-components.js (1)

476-487: Guard against missing keywords to prevent runtime errors.

The filter assumes icon.keywords exists and is a string. If undefined, this will throw a runtime error.

This issue was previously flagged in an earlier review. Apply the suggested fix:

 filteredIcons: function() {
     var self = this;
     if (!this.icons.length) return [];
     
     if (!this.searchTerm) return this.icons;
     
     var searchLower = this.searchTerm.toLowerCase();
     return this.icons.filter(function(icon) {
-        return icon.name.toLowerCase().indexOf(searchLower) !== -1 ||
-               icon.keywords.toLowerCase().indexOf(searchLower) !== -1;
+        var kw = (icon.keywords || '').toString().toLowerCase();
+        return (icon.name || '').toString().toLowerCase().indexOf(searchLower) !== -1 ||
+               kw.indexOf(searchLower) !== -1;
     });
 }
admin/form-builder/assets/js/components/field-icon_selector/index.js (1)

52-55: Guard against missing keywords to prevent runtime errors.

The filter assumes icon.keywords is always defined. When undefined, toLowerCase() will throw a runtime error.

Apply this fix:

 return this.icons.filter(function(icon) {
-    return icon.name.toLowerCase().indexOf(searchLower) !== -1 ||
-           icon.keywords.toLowerCase().indexOf(searchLower) !== -1;
+    var kw = (icon.keywords || '').toString().toLowerCase();
+    return (icon.name || '').toString().toLowerCase().indexOf(searchLower) !== -1 ||
+           kw.indexOf(searchLower) !== -1;
 });
🧹 Nitpick comments (1)
admin/form-builder/assets/js/components/field-icon_selector/index.js (1)

1-109: Consolidate field-icon_selector component into one file
Duplicate definitions exist in assets/js/wpuf-form-builder-components.js and assets/js/components/field-icon_selector/index.js; remove the redundant file and ensure only the canonical component is enqueued.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 66e6262 and c38558f.

📒 Files selected for processing (4)
  • admin/form-builder/assets/js/components/field-icon_selector/index.js (1 hunks)
  • assets/js/wpuf-form-builder-components.js (1 hunks)
  • includes/Admin/Forms/Admin_Form_Builder.php (3 hunks)
  • includes/Assets.php (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • includes/Assets.php
🔇 Additional comments (1)
includes/Admin/Forms/Admin_Form_Builder.php (1)

428-458: LGTM! Robust error handling for icon configuration.

The get_icon_config() method properly handles missing files and JSON parsing errors with safe fallbacks. The use of null coalescing operators ensures data integrity even if the JSON structure is incomplete.

];
}

return [
Copy link
Member

Choose a reason for hiding this comment

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

please add a filter hook here

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done @sapayth vai

@sapayth sapayth added needs: author reply This PR needs author feedback or code changes and removed needs: dev review This PR needs review by a developer labels Oct 15, 2025
@arifulhoque7 arifulhoque7 added needs: dev review This PR needs review by a developer and removed needs: author reply This PR needs author feedback or code changes labels Oct 16, 2025
Copy link

@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 c38558f and 5c7835b.

📒 Files selected for processing (1)
  • includes/Admin/Forms/Admin_Form_Builder.php (3 hunks)
🔇 Additional comments (2)
includes/Admin/Forms/Admin_Form_Builder.php (2)

178-180: LGTM!

The icon configuration is loaded cleanly and integrated into the existing script localization flow.


209-210: LGTM!

The icon data is correctly added to the localized script data. The get_icon_config() method guarantees these keys exist, so direct array access is safe.

Comment on lines +428 to +475
/**
* Get icon configuration from JSON file
*
* @since 4.2.0
*
* @return array
*/
protected function get_icon_config() {
$config_file = WPUF_ROOT . '/config/icons-config.json';

if ( ! file_exists( $config_file ) ) {
$icon_config = [
'icons' => [],
'defaultIcons' => [],
];

/** This filter is documented in includes/Admin/Forms/Admin_Form_Builder.php */
return apply_filters( 'wpuf_form_builder_icon_config', $icon_config );
}

$config = json_decode( file_get_contents( $config_file ), true );

if ( json_last_error() !== JSON_ERROR_NONE ) {
$icon_config = [
'icons' => [],
'defaultIcons' => [],
];

/** This filter is documented in includes/Admin/Forms/Admin_Form_Builder.php */
return apply_filters( 'wpuf_form_builder_icon_config', $icon_config );
}

$icon_config = [
'icons' => $config['icons'] ?? [],
'defaultIcons' => $config['defaultIcons'] ?? [],
];

/**
* Filter the icon configuration for form builder
*
* @since WPUF_SINCE
*
* @param array $icon_config The icon configuration array
* - icons: array of icon data
* - defaultIcons: array of default icons
*/
return apply_filters( 'wpuf_form_builder_icon_config', $icon_config );
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Update the @since placeholder in filter documentation.

The filter documentation at line 468 uses WPUF_SINCE as a placeholder. Replace it with the actual version (likely 4.2.0 based on the method's @since tag).

Apply this diff to fix the placeholder:

     /**
      * Filter the icon configuration for form builder
      *
-     * @since WPUF_SINCE
+     * @since 4.2.0
      *
      * @param array $icon_config The icon configuration array
      *                           - icons: array of icon data
      *                           - defaultIcons: array of default icons
      */

Consider caching the icon configuration for better performance.

The icon config is read from disk and decoded on every admin page load. While this is admin-only and the file is likely small, adding transient-based caching could improve performance, especially if the icon list grows.

Example caching approach:

protected function get_icon_config() {
    // Check cache first
    $icon_config = get_transient( 'wpuf_icon_config' );
    if ( false !== $icon_config ) {
        return apply_filters( 'wpuf_form_builder_icon_config', $icon_config );
    }

    $config_file = WPUF_ROOT . '/config/icons-config.json';

    // ... existing file reading logic ...

    // Cache for 1 day
    set_transient( 'wpuf_icon_config', $icon_config, DAY_IN_SECONDS );

    return apply_filters( 'wpuf_form_builder_icon_config', $icon_config );
}

Don't forget to clear the transient when the plugin is updated or when the config file changes.


Excellent error handling and structure.

The method has robust defensive programming:

  • Gracefully handles missing files
  • Validates JSON decoding
  • Uses null coalescing for safe array access
  • Applies filter consistently across all code paths
  • Returns a predictable structure even on errors
🤖 Prompt for AI Agents
In includes/Admin/Forms/Admin_Form_Builder.php around lines 428-475, replace the
placeholder "@since WPUF_SINCE" in the filter docblock with the real version
"4.2.0", and add transient-based caching around the existing logic: first try
get_transient('wpuf_icon_config') and if present return apply_filters(...),
otherwise perform the current file-read/JSON-decode flow, then
set_transient('wpuf_icon_config', $icon_config, DAY_IN_SECONDS) before
returning; ensure existing error handling and the apply_filters call remain
unchanged and plan to clear the transient when the plugin is updated or the
config file changes.

@sapayth sapayth added Dev Review Done and removed needs: dev review This PR needs review by a developer labels Oct 20, 2025
@sapayth sapayth merged commit a317a58 into weDevsOfficial:develop Oct 20, 2025
1 of 2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Dev Review Done QA Approved This PR is approved by the QA team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants