Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,20 @@ class="wpuf-group wpuf-rounded-lg hover:!wpuf-bg-green-50 wpuf-transition wpuf-d
:class="parseInt(editing_form_id) === parseInt(field.id) ? 'wpuf-bg-green-50 wpuf-border-green-400' : 'wpuf-border-transparent'"
class="wpuf-flex wpuf-justify-between wpuf-p-6 wpuf-rounded-t-md wpuf-border-t wpuf-border-r wpuf-border-l wpuf-border-dashed group-hover:wpuf-border-green-400 group-hover:wpuf-cursor-pointer !wpuf-pb-3">
<div v-if="!(is_full_width(field.template) || is_pro_preview(field.template))" class="wpuf-w-1/4 wpuf-flex wpuf-items-center">
<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>
Comment on lines +27 to +30
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

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

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

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

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

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

<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>
Comment on lines 31 to 37
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix ternary precedence in the label “for” binding

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

-                        :for="'wpuf-' + field.name ? field.name : 'cls'"
+                        :for="'wpuf-' + (field.name ? field.name : 'cls')"
📝 Committable suggestion

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

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

<span v-if="field.icon && field.show_icon === 'yes'"
class="wpuf-field-label-icon wpuf-inline-flex wpuf-items-center wpuf-ml-2"
v-html="field.icon">
<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>
Comment on lines +38 to 41
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

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

Match the left icon fix.

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

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

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

</div>
<div
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,16 @@
data-source="stage"
>
<div v-if="!is_full_width(field.template)" class="wpuf-label">
<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>
Comment on lines +20 to +23
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Hide icons when label is hidden; add aria-hidden

Match v4-1 fixes for left icon.

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

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

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

<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>
Comment on lines 24 to 26
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix ternary precedence in the label “for” binding

Ensure the wpuf- prefix is applied correctly.

-                <label v-if="!is_invisible(field)" :for="'wpuf-' + field.name ? field.name : 'cls'">
+                <label v-if="!is_invisible(field)" :for="'wpuf-' + (field.name ? field.name : 'cls')">
📝 Committable suggestion

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

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

<span v-if="field.icon && field.show_icon === 'yes'"
class="wpuf-field-label-icon wpuf-inline-flex wpuf-items-center wpuf-ml-2"
v-html="field.icon">
<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>
Comment on lines +27 to 30
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Right icon symmetry (visibility + aria)

Same adjustment for the right-aligned icon.

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

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

Suggested change
<span v-if="field.show_icon === 'yes' && field.field_icon && field.icon_position === 'right_label'"
class="wpuf-field-label-icon wpuf-inline-flex wpuf-items-center wpuf-ml-2">
<i :class="[field.field_icon, 'wpuf-field-icon']"></i>
</span>
<span v-if="field.show_icon === 'yes' && field.field_icon && field.icon_position === 'right_label' && !is_invisible(field)"
class="wpuf-field-label-icon wpuf-inline-flex wpuf-items-center wpuf-ml-2">
<i :class="[field.field_icon, 'wpuf-field-icon']" aria-hidden="true"></i>
</span>
🤖 Prompt for AI Agents
In admin/form-builder/assets/js/components/builder-stage/template.php around
lines 27 to 30, the right-aligned icon span needs the same visibility and
accessibility adjustments as the left icon: keep the existing v-if condition but
ensure the inner <i> is marked decorative (add aria-hidden="true" and
tabindex="-1") and/or include role="img" only if it conveys meaningful
information; mirror the left-icon changes exactly so the icon is hidden from
assistive tech when decorative and remains conditionally rendered by the same
field.show_icon check.

</div>

Expand Down
109 changes: 109 additions & 0 deletions admin/form-builder/assets/js/components/field-icon_selector/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
Vue.component('field-icon_selector', {
template: '#tmpl-wpuf-field-icon_selector',

mixins: [
wpuf_mixins.option_field_mixin
],

mounted: function() {
document.addEventListener('click', this.handleClickOutside);
},

data: function () {
return {
showIconPicker: false,
searchTerm: '',
icons: wpuf_form_builder.icons || []
};
},

computed: {
value: {
get: function () {
return this.editing_form_field[this.option_field.name];
},

set: function (value) {
this.$store.commit('update_editing_form_field', {
editing_field_id: this.editing_form_field.id,
field_name: this.option_field.name,
value: value
});
}
},

selectedIconDisplay: function() {
if (this.value) {
var icon = this.icons.find(function(item) {
return item.class === this.value;
}.bind(this));
return icon ? icon.name : this.value;
}
return 'Select an icon';
},

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;
});
}
},

watch: {
'editing_form_field.show_icon': function(newVal, oldVal) {
// When show_icon changes from 'no' to 'yes' and field_icon is empty or 'fas fa-0'
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 = wpuf_form_builder.defaultIcons || {};

// Get the field type/template
var fieldType = this.editing_form_field.template || this.editing_form_field.input_type || 'text';

// Set the default icon based on field type
var defaultIcon = defaultIcons[fieldType] || 'fa-solid fa-circle';

this.$store.commit('update_editing_form_field', {
editing_field_id: this.editing_form_field.id,
field_name: 'field_icon',
value: defaultIcon
});
}
}
}
},

methods: {

selectIcon: function(iconClass) {
this.value = iconClass;
this.showIconPicker = false;
},

clearIcon: function() {
this.value = '';
this.showIconPicker = false;
},

togglePicker: function() {
this.showIconPicker = !this.showIconPicker;
},

handleClickOutside: function(event) {
if (!this.$el.contains(event.target)) {
this.showIconPicker = false;
}
}
},

beforeDestroy: function() {
document.removeEventListener('click', this.handleClickOutside);
}
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<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>
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ class="wpuf-block text-sm/6 wpuf-font-medium wpuf-text-gray-900 !wpuf-mb-0">
type="radio"
:name="'radio_' + editing_form_field.id + '_' + option_field.name"
:value="key"
:name="option_field.name"
v-model="value"
:class="builder_class_names('radio')">
{{ option }}
Expand All @@ -35,7 +34,6 @@ class="wpuf-flex wpuf-items-center"
:name="'radio_' + editing_form_field.id + '_' + option_field.name"
:value="key"
v-model="value"
:name="option_field.name"
:class="builder_class_names('radio')">
{{ option }}
</label>
Expand Down
28 changes: 28 additions & 0 deletions admin/form-builder/assets/js/form-builder.js
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,16 @@

// add new form field element
add_form_field_element: function (state, payload) {
// 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';
}
Comment on lines +188 to +197
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Mirror normalization here to avoid non-reactive writes

Same rationale as in assets/js/wpuf-form-builder.js. Normalize in set_form_fields and in nested add/clone paths so toggling icon settings on older forms remains reactive.

@@
-            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);
+            },
@@
             add_column_inner_field_element: function (state, payload) {
@@
-                } else {
+                } 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) {
@@
-                state.form_fields[repeatFieldIndex].inner_fields.splice(payload.toIndex, 0, payload.field);
+                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 helpers (once in this file):

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 admin/form-builder/assets/js/form-builder.js around lines 188 to 197, the
code directly assigns missing icon properties (show_icon, field_icon,
icon_position) which can create non-reactive writes; add a pair of helper
functions once in this file—ensureIconDefaults(obj) that uses Vue.set to add
show_icon (default 'no'), field_icon (default ''), and icon_position (default
'left_label') when missing, and ensureIconDefaultsRecursively(field) that calls
ensureIconDefaults and walks inner_fields for column_field and repeat_field
templates to apply recursively; then replace the direct property
checks/assignments in set_form_fields and the nested add/clone code paths to
call ensureIconDefaultsRecursively on each field so older forms become reactive
when toggling icon settings.


state.form_fields.splice(payload.toIndex, 0, payload.field);
var sprintf = wp.i18n.sprintf;
Expand Down Expand Up @@ -729,6 +739,24 @@
},

mounted: function () {
// Ensure all fields have proper default values for icon settings when editing existing forms
this.$store.state.form_fields.forEach(function(field) {
// If show_icon is not set in the database, default it to 'no'
if (field.show_icon === undefined || field.show_icon === null) {
field.show_icon = 'no';
}

// If field_icon is not set in the database, set it to default icon fas fa-0
if (field.field_icon === undefined || field.field_icon === null) {
field.field_icon = 'fas fa-0';
}

// If icon_position is not set, default it to 'left_label'
if (field.icon_position === undefined || field.icon_position === null) {
field.icon_position = 'left_label';
}
});

// Check if there are hidden custom taxonomy fields and show warning
if (wpuf_form_builder.has_hidden_taxonomies && !wpuf_form_builder.is_pro_active) {
var self = this;
Expand Down
7 changes: 7 additions & 0 deletions admin/form-builder/assets/less/form-builder.less
Original file line number Diff line number Diff line change
Expand Up @@ -1537,5 +1537,12 @@ span.pro-icon svg path {
fill: #fff;
}

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

@import "builder-responsive.less";

9 changes: 9 additions & 0 deletions assets/css/admin/form-builder.css
Original file line number Diff line number Diff line change
Expand Up @@ -4580,6 +4580,10 @@ input.wpuf-tab:checked + .wpuf-tab-content,
justify-content: space-evenly;
}

.wpuf-gap-1 {
gap: 0.25rem;
}

.wpuf-gap-12 {
gap: 3rem;
}
Expand Down Expand Up @@ -6820,6 +6824,11 @@ button.swal2-cancel.swal2-styled.swal2-default-outline {
color: rgb(5 150 105 / var(--tw-text-opacity));
}

.hover\:wpuf-text-red-500:hover {
--tw-text-opacity: 1;
color: rgb(239 68 68 / var(--tw-text-opacity));
}

.hover\:wpuf-text-white:hover {
--tw-text-opacity: 1;
color: rgb(255 255 255 / var(--tw-text-opacity));
Expand Down
7 changes: 7 additions & 0 deletions assets/css/wpuf-form-builder.css
Original file line number Diff line number Diff line change
Expand Up @@ -1237,6 +1237,13 @@ span.pro-icon svg {
span.pro-icon svg path {
fill: #fff;
}
/* Form Builder Field Icons */
.wpuf-field-label-icon .wpuf-field-icon {
font-size: 20px;
color: #059669;
/* emerald-600 */
margin-right: 6px;
}
@media (min-width: 768px) and (max-width: 991px) {
#wpuf-form-builder {
width: 100% !important;
Expand Down
Loading
Loading