-
Notifications
You must be signed in to change notification settings - Fork 151
Feature/dynamic field icons #1701
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feature/dynamic field icons #1701
Conversation
- 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]>
WalkthroughAdds 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
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related issues
Possibly related PRs
Suggested labels
Suggested reviewers
Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this 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 initsMinor: 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 bundlesExtract 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 triggerMake 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 popoverHelps 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-accessibleThe “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 asymmetricalGlobal 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 colorUse 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 updatesConfirm 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 LESSIf 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 repeatedstring.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
.distignoresnippet.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 callfa-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
.scssfrom 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
⛔ Files ignored due to path filters (232)
assets/vendor/font-awesome-7/js/all.min.jsis excluded by!**/*.min.jsassets/vendor/font-awesome-7/js/brands.min.jsis excluded by!**/*.min.jsassets/vendor/font-awesome-7/js/conflict-detection.min.jsis excluded by!**/*.min.jsassets/vendor/font-awesome-7/js/fontawesome.min.jsis excluded by!**/*.min.jsassets/vendor/font-awesome-7/js/regular.min.jsis excluded by!**/*.min.jsassets/vendor/font-awesome-7/js/solid.min.jsis excluded by!**/*.min.jsassets/vendor/font-awesome-7/js/v4-shims.min.jsis excluded by!**/*.min.jsassets/vendor/font-awesome-7/sprites-full/brands.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/sprites-full/regular.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/sprites-full/solid.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/sprites/brands.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/sprites/regular.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/sprites/solid.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/11ty.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/42-group.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/500px.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/accessible-icon.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/accusoft.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/adn.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/adversal.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/affiliatetheme.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/airbnb.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/algolia.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/alipay.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/amazon-pay.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/amazon.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/amilia.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/android.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/angellist.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/angrycreative.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/angular.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/app-store-ios.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/app-store.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/apper.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/apple-pay.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/apple.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/artstation.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/asymmetrik.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/atlassian.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/audible.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/autoprefixer.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/avianex.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/aviato.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/aws.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/bandcamp.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/battle-net.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/behance-square.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/behance.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/bilibili.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/bimobject.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/bitbucket.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/bitcoin.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/bity.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/black-tie.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/blackberry.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/blogger-b.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/blogger.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/bluesky.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/bluetooth-b.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/bluetooth.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/bootstrap.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/bots.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/brave-reverse.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/brave.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/btc.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/buffer.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/buromobelexperte.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/buy-n-large.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/buysellads.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/canadian-maple-leaf.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/cash-app.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/cc-amazon-pay.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/cc-amex.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/cc-apple-pay.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/cc-diners-club.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/cc-discover.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/cc-jcb.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/cc-mastercard.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/cc-paypal.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/cc-stripe.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/cc-visa.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/centercode.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/centos.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/chrome.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/chromecast.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/cloudflare.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/cloudscale.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/cloudsmith.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/cloudversify.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/cmplid.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/codepen.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/codiepie.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/confluence.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/connectdevelop.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/contao.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/cotton-bureau.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/cpanel.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/creative-commons-by.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/creative-commons-nc-eu.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/creative-commons-nc-jp.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/creative-commons-nc.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/creative-commons-nd.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/creative-commons-pd-alt.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/creative-commons-pd.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/creative-commons-remix.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/creative-commons-sa.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/creative-commons-sampling-plus.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/creative-commons-sampling.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/creative-commons-share.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/creative-commons-zero.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/creative-commons.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/critical-role.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/css.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/css3-alt.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/css3.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/cuttlefish.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/d-and-d-beyond.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/d-and-d.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/dailymotion.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/dart-lang.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/dashcube.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/debian.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/deezer.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/delicious.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/deploydog.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/deskpro.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/dev.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/deviantart.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/dhl.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/diaspora.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/digg.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/digital-ocean.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/discord.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/discourse.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/disqus.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/dochub.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/docker.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/draft2digital.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/dribbble-square.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/dribbble.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/dropbox.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/drupal.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/duolingo.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/dyalog.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/earlybirds.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/ebay.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/edge-legacy.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/edge.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/elementor.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/eleventy.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/ello.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/ember.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/empire.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/envira.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/erlang.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/ethereum.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/etsy.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/evernote.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/expeditedssl.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/facebook-f.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/facebook-messenger.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/facebook-square.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/facebook.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/fantasy-flight-games.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/fedex.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/fedora.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/figma.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/files-pinwheel.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/firefox-browser.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/firefox.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/first-order-alt.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/first-order.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/firstdraft.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/flickr.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/flipboard.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/flutter.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/fly.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/font-awesome-alt.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/font-awesome-flag.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/font-awesome-logo-full.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/font-awesome.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/fonticons-fi.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/fonticons.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/fort-awesome-alt.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/fort-awesome.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/forumbee.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/foursquare.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/free-code-camp.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/freebsd.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/fulcrum.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/galactic-republic.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/galactic-senate.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/get-pocket.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/gg-circle.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/gg.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/git-alt.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/git-square.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/git.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/github-alt.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/github-square.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/github.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/gitkraken.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/gitlab-square.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/gitlab.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/gitter.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/glide-g.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/glide.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/gofore.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/golang.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/goodreads-g.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/goodreads.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/google-drive.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/google-pay.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/google-play.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/google-plus-g.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/google-plus-square.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/google-plus.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/google-scholar.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/google-wallet.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/google.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/gratipay.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/grav.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/gripfire.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/grunt.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/guilded.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/gulp.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/hacker-news-square.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/hacker-news.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/hackerrank.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/hashnode.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/hips.svgis excluded by!**/*.svgassets/vendor/font-awesome-7/svgs-full/brands/hire-a-helper.svgis 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)
| <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> |
There was a problem hiding this comment.
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.
| <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.
| <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> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
| <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.
| <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> |
There was a problem hiding this comment.
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.
| <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.
| <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> |
There was a problem hiding this comment.
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.
| <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.
| <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> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
| <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.
| <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> |
There was a problem hiding this comment.
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.
| <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.
| <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> |
There was a problem hiding this comment.
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.
| <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> |
| // 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'; | ||
| } |
There was a problem hiding this comment.
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.
sapayth
left a comment
There was a problem hiding this 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() { |
There was a problem hiding this comment.
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 = { |
There was a problem hiding this comment.
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'; |
There was a problem hiding this comment.
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
There was a problem hiding this 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
⛔ Files ignored due to path filters (2)
assets/js/forms-list.min.jsis excluded by!**/*.min.jsassets/js/subscriptions.min.jsis 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.
ae98dd4 to
511e0e7
Compare
|
done @sapayth vai |
There was a problem hiding this 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
📒 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 accessibleRepo 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 useicons-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 availabilityIcons 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.
| 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; | ||
| }); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
| 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.
| 'src' => WPUF_ASSET_URI . '/vendor/font-awesome/css/all.min.css', | ||
| 'version' => '7.0.1', | ||
| ], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 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.
includes/WPUF_Icon_Loader.php
Outdated
| 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 ) | ||
| ]); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 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=jsLength 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/**' || trueLength 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' || trueLength 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 || trueLength 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.
includes/WPUF_Icon_Loader.php
Outdated
| ['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'], | ||
| ]; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
| ['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'], | |
| ]; | |
| } |
includes/WPUF_Icon_Loader.php
Outdated
| */ | ||
| private function get_common_icons() { | ||
| return [ | ||
| ['class' => 'fas fa-home', 'name' => 'Home', 'filename' => 'home', 'style' => 'solid'], |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done @sapayth vai
There was a problem hiding this 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.keywordsexists 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.keywordsis 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: Consolidatefield-icon_selectorcomponent into one file
Duplicate definitions exist inassets/js/wpuf-form-builder-components.jsandassets/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
📒 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 [ |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done @sapayth vai
There was a problem hiding this 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
📒 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.
| /** | ||
| * 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 ); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
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:
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
Considerations
Acceptance Criteria
Summary by CodeRabbit
New Features
Bug Fixes
Style
Chores