Skip to content
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

enhance: form builder blank form, form field icons #1506

Open
wants to merge 58 commits into
base: develop
Choose a base branch
from

Conversation

sapayth
Copy link
Member

@sapayth sapayth commented Jan 1, 2025

fixes #661

For the form builder revamp add blank-form state. update the field icons as per design and do some other small design changes.

Summary by CodeRabbit

Release Notes

New Features

  • Added a new form builder interface (v4.1) with enhanced user experience.
  • Introduced dynamic form field search functionality.
  • Improved styling and responsiveness across form components.
  • Added Cloudflare Turnstile support for form fields.
  • New modal component for selecting post form templates with enhanced layout and functionality.
  • Introduced a new Vue component for managing form fields in the sidebar.
  • Added Tailwind CSS for improved styling across components.

Improvements

  • Refined form template selection process.
  • Enhanced form field styling with utility classes.
  • Improved tooltip and help text presentation.
  • Updated icons for various form fields.
  • Optimized asset loading and management.
  • Enhanced user interface for form settings with improved navigation and visibility.
  • Enhanced visual presentation of form preview stages.
  • Streamlined CSS and JavaScript for better performance.
  • Enhanced error handling for undefined indices in form field management.

Bug Fixes

  • Fixed potential undefined index notices in form field handling.
  • Improved error handling in form field interactions.

Performance

  • Optimized form builder asset loading.

Compatibility

  • Added version-specific handling for Pro plugin features.
  • Improved support for different WordPress environments.

Styling

  • Implemented modern, responsive design using utility classes.
  • Enhanced visual feedback for form interactions.
  • Updated background and border styles for form components.

sapayth added 30 commits October 7, 2024 17:59
commit daae343
Author: Sapayth Hossain <[email protected]>
Date:   Fri Oct 25 10:21:05 2024 +0600

    fix logo, minor css

commit 7590512
Author: Sapayth Hossain <[email protected]>
Date:   Thu Oct 17 13:00:12 2024 +0600

    pro icon and link

commit b720564
Author: Sapayth Hossain <[email protected]>
Date:   Wed Oct 16 17:31:46 2024 +0600

    action buttons

commit 743860f
Author: Sapayth Hossain <[email protected]>
Date:   Wed Oct 16 13:10:14 2024 +0600

    various fields

    time, phone field, pro fields, image, file, recaptcha, hidden fields

commit e58e788
Merge: 2b12da4 f92a621
Author: Sapayth Hossain <[email protected]>
Date:   Tue Oct 15 17:25:44 2024 +0600

    Merge remote-tracking branch 'upstream/develop' into enhance/form_builder_content_body_ui_redesign

commit 2b12da4
Author: Sapayth Hossain <[email protected]>
Date:   Tue Oct 15 17:24:24 2024 +0600

    column field, section break

commit 63f6663
Author: Sapayth Hossain <[email protected]>
Date:   Mon Oct 14 21:47:26 2024 +0600

    regular fields
Copy link

coderabbitai bot commented Jan 1, 2025

Walkthrough

The pull request introduces comprehensive updates across multiple files in the WordPress User Frontend plugin, focusing on enhancing the form builder interface, updating styling, and improving component functionality. The changes span various aspects of the plugin, including Vue.js components, CSS styling, form templates, and administrative interfaces. Key modifications include introducing new form builder versions, refining UI components, and updating asset management.

Changes

File/Group Change Summary
Vue Components Added new components like builder-stage-v4-1, form-fields-v4-1 with enhanced functionality
Form Builder JS Updated Vuex store with new state properties and mutations for improved form handling
CSS/LESS Files Streamlined styling, removed specific field size constraints, updated form layout
Admin Templates Introduced version-specific templates with improved UI and interaction
Mixins Enhanced form field and option field mixins with new methods and default values

Assessment against linked issues

Objective Addressed Explanation
Update Appsero SDK [#661] Changes in Lib/Appsero/Client.php update the client method for retrieving plugin data

Poem

🐰 A form builder's tale of delight,
Refactored code, a sparkling sight!
Vue components dance with grace,
Styles aligned in every space.
CodeRabbit hops with pure glee! 🎉


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 10

🧹 Nitpick comments (66)
admin/form-builder/assets/js/components/form-textarea_field/template.php (1)

8-8: Consistent use of builder_class_names is recommended across all form components.

Switching to builder_class_names('textareafield') aligns with the new class naming approach. Ensure all other fields' classes follow the same pattern for uniformity.

assets/less/frontend-forms.less (1)

Line range hint 1-1000: Consider implementing CSS Custom Properties

The codebase heavily uses LESS variables for colors and dimensions. Consider gradually migrating to CSS Custom Properties (CSS Variables) for better runtime customization and theme support.

Example implementation:

-@borderColor: #eee;
-@mainColor: #64C3DE;
+:root {
+  --wpuf-border-color: #eee;
+  --wpuf-main-color: #64C3DE;
+}

This would allow runtime theme changes and better maintainability.

includes/Admin/Forms/Post/Templates/Form_Template.php (1)

85-89: Condense style enqueue logic.
Although these lines ensure backward compatibility for different versions, consider condensing the logic into a single version-check utility function. This keeps the enqueue code DRY and more maintainable.

includes/Admin/Menu.php (2)

120-121: Consider removing or utilizing $pro_templates

Currently, $pro_templates is assigned but never used. Keeping unused variables can introduce confusion and clutter. Suggest removing it if not needed or utilizing it if it serves a purpose.

 $registry       = wpuf_get_post_form_templates();
-$pro_templates  = wpuf_get_pro_form_previews();

124-128: Ensure consistent translation and branding for the mailto link

The $footer_help variable leverages sprintf with an inline translator comment. Confirm that the user-facing text aligns with your branding guidelines and expected translation context.

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

53-57: Consider making these classes configurable for future flexibility.

Right now, action_button_classes returns a static string of utility classes. If you anticipate needing to update or toggle classes conditionally (e.g., based on props, state, or theming), consider using a more dynamic approach—for example, storing possible class variants in a data property or a computed property that checks relevant state.


95-129: Extract repeated classes into a lookup object for cleaner, DRY code.

Using a switch statement is fine, but consider refactoring the repeated string literals into an external object mapping each type to a class string. For example:

const typeClassMap = {
  text: "...",
  textfield: "...",
  ...
};

builder_class_names(type_class) {
  const commonClasses = typeClassMap[type_class] || '';
  return [ /* ... */ commonClasses ];
}

This approach may simplify maintenance and readability by centralizing your classes in a single structure.

includes/Admin/template-parts/modal-v4.1.php (2)

107-109: Add security attributes to external link
When linking to external sites in a new tab, it's best practice to include rel="noopener noreferrer" to reduce the risk of window manipulation from the linked page.

-<a href="<?php echo esc_url( Pro_Prompt::get_upgrade_to_pro_popup_url() ); ?>"
-   target="_blank"
-   class="wpuf-btn-primary wpuf-flex wpuf-items-center wpuf-w-max"
-   title="<?php echo esc_attr( $template->get_title() ); ?>" >
+<a href="<?php echo esc_url( Pro_Prompt::get_upgrade_to_pro_popup_url() ); ?>"
+   target="_blank"
+   rel="noopener noreferrer"
+   class="wpuf-btn-primary wpuf-flex wpuf-items-center wpuf-w-max"
+   title="<?php echo esc_attr( $template->get_title() ); ?>" >

131-168: Consider adding an overlay click-to-close feature
Closing the modal only via the close button or the ESC key might be less intuitive for users. Consider listening for clicks on the modal’s background/overlay to provide a more standard dismissal option.

admin/form-builder/assets/js/components/form-fields-v4-1/index.js (3)

30-38: jQuery UI draggable
The draggable setup is properly targeting selector .panel-form-field-buttons .wpuf-field-button. Consider wrapping it in a condition or try-catch to ensure it doesn't error if the expected elements are missing.


68-81: Simplify null checks with optional chaining
Static analysis suggests using optional chaining. Replace validator && validator.msg with validator?.msg for brevity.

- if (validator && validator.msg) {
+ if (validator?.msg) {
🧰 Tools
🪛 Biome (1.9.4)

[error] 71-71: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


92-115: Avoid aliasing this
At line 94, the variable self is assigned to this. Using an arrow function or direct this calls is generally preferable for readability.

- var self = this;
+ // rely on arrow functions or use `this` directly
🧰 Tools
🪛 Biome (1.9.4)

[error] 94-94: This aliasing of this is unnecessary.

Arrow functions inherits this from their enclosing scope.
Safe fix: Use this instead of an alias.

(lint/complexity/noUselessThisAlias)

assets/js/wpuf-form-builder.js (4)

489-525: Branching for post form vs normal form
The code for setting up tabs, clipboard, and tooltips is repeated. Consider DRY (Don't Repeat Yourself) patterns if possible.


530-530: Redeclaring settings_tabs
Static analysis indicates settings_tabs is declared again in this scope (also declared at line 491). Consider renaming to avoid confusion.

- var settings_tabs = $('#wpuf-form-builder-settings .nav-tab'),
-     settings_tab_contents = ...
+ var secondary_settings_tabs = $('#wpuf-form-builder-settings .nav-tab'),
+     settings_tab_contents = ...
🧰 Tools
🪛 Biome (1.9.4)

[error] 530-530: Shouldn't redeclare 'settings_tabs'. Consider to delete it or rename it.

'settings_tabs' is defined here:

(lint/suspicious/noRedeclare)


538-538: Redeclaring clipboard
The variable clipboard was also declared earlier at line 499. Consider a different identifier or scoping to avoid overshadowing.

🧰 Tools
🪛 Biome (1.9.4)

[error] 538-538: Shouldn't redeclare 'clipboard'. Consider to delete it or rename it.

'clipboard' is defined here:

(lint/suspicious/noRedeclare)


541-541: Redeclaring self
var self = this; is also declared earlier. Prefer directly using arrow functions or sticking to one self usage if necessary.

🧰 Tools
🪛 Biome (1.9.4)

[error] 541-541: Shouldn't redeclare 'self'. Consider to delete it or rename it.

'self' is defined here:

(lint/suspicious/noRedeclare)

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

489-525: Conditional form type logic
As in the previous file, consider refactoring the repeated logic for settings tabs and clipboard to reduce duplication.


530-530: Avoid redeclaring settings_tabs
Rename or restructure to prevent overshadowing from the earlier declaration in the same scope.

🧰 Tools
🪛 Biome (1.9.4)

[error] 530-530: Shouldn't redeclare 'settings_tabs'. Consider to delete it or rename it.

'settings_tabs' is defined here:

(lint/suspicious/noRedeclare)


538-538: clipboard overshadowing
Rename or scope properly, as it’s also declared in line 499.

🧰 Tools
🪛 Biome (1.9.4)

[error] 538-538: Shouldn't redeclare 'clipboard'. Consider to delete it or rename it.

'clipboard' is defined here:

(lint/suspicious/noRedeclare)


541-541: self overshadowing
Reusing var self = this; is unnecessary. Prefer an arrow function if you need lexical scope.

🧰 Tools
🪛 Biome (1.9.4)

[error] 541-541: Shouldn't redeclare 'self'. Consider to delete it or rename it.

'self' is defined here:

(lint/suspicious/noRedeclare)

assets/js-templates/form-components.php (3)

85-91: Provide additional user guidance for blank form state
These lines introduce a helpful blank state with an illustration and descriptive text. It might be beneficial to include more specific instructions, such as “Drag and drop fields from the sidebar” or “Click on a field to configure its settings,” to further guide new users.


306-320: Multi-select changes
The multi-select approach is well-handled. For large sets of options, ensure that the component doesn't become unwieldy. Lazy-loading or a search integration might be worth adding later.


1047-1157: New form-fields-v4-1 component
This block introduces a cleaner UI for searching and adding form fields. The search field and dynamic panel toggles are an excellent user experience improvement. As a minor improvement, consider debouncing the search input to reduce performance overhead for large forms.

admin/form-builder/assets/js/components/form-email_address/template.php (1)

4-4: Use array-based class binding for improved readability
While combining class_names('email') and builder_class_names('text') via string concatenation works fine, consider using an array-based syntax for improved clarity and to avoid potential spacing issues:

-:class="class_names('email') + builder_class_names('text')"
+:class="[class_names('email'), builder_class_names('text')]"
admin/form-builder/assets/js/components/field-textarea/template.php (1)

2-2: Ensure label is accessible
Adding a for attribute on the <label> that matches the id of the <textarea> would further improve accessibility by explicitly linking the label and the textarea.

admin/form-builder/assets/js/components/form-recaptcha/template.php (1)

7-7: Provide descriptive alt text
Consider providing a descriptive alt text for the placeholder image. Having an empty alt value might be fine for purely decorative images, but a short description like "reCaptcha placeholder" can improve accessibility for screen readers.

admin/form-builder/assets/js/components/field-option-pro-feature-alert/template.php (1)

1-6: Consider improving the alt text for accessibility.
While "pro icon" is acceptable, a more descriptive alt text (e.g., "Pro feature icon") might better convey the meaning to screen reader users.

admin/form-builder/assets/js/components/help-text/index.js (1)

20-23: Consider using a Vue-based tooltip approach instead of jQuery.
While the tooltip configuration works, relying on jQuery may lead to maintainability issues if your project moves away from jQuery in future versions. You might explore a pure Vue-based tooltip library to keep your stack consistent.

admin/form-builder/assets/js/components/field-checkbox/template.php (1)

8-8: Dynamic class binding for flexibility.
Using :class="builder_class_names('checkbox')" is an excellent approach to unify styling across different build contexts. Provide documentation on how builder_class_names is computed so new team members can extend or modify it easily.

admin/form-builder/assets/js/components/form-dropdown_field/template.php (1)

13-13: Semantic improvement for help text.
Switching from <span> to <p> provides better readability and semantic structure. Use additional ARIA attributes if you need more accessibility cues, for example linking help text with the form control using aria-describedby.

admin/form-builder/assets/js/components/field-text-meta/template.php (1)

1-13: Ensure label and input maintain full accessibility compliance.

The addition of :for="option_field.title" is a step in the right direction for accessibility, but consider binding an actual id to the <input> so that the for attribute references a valid ID. Matching for/id pairs provide better accessibility for screen reader users.

admin/form-builder/assets/js/components/field-select/index.js (1)

8-13: Consider i18n and default states for the new dropdown.

The newly introduced showOptions and selectedOption properties effectively control the dropdown’s visibility and display text. However, the default string 'Select an option' may need translation for internationalization. Align the UI text with your localization strategy to ensure usability across different languages.

admin/form-builder/assets/js/components/form-post_content/template.php (1)

14-14: Consider removing or replacing <br> for better semantic structure
The <br> tag is acceptable for short line breaks, but for a more robust structure, consider using CSS margins or spacing utilities for better maintainability.

admin/form-builder/assets/js/components/form-image_upload/template.php (1)

4-16: Use consistent button label logic and accessibility.
The updated <a> tag with conditional button labels using SVG icons is a welcome improvement. Make sure the button text (e.g., "Select Image") is either accessible through ARIA attributes or remains visible for screen readers.

admin/form-builder/assets/js/components/field-select/template.php (1)

20-21: Separate concerns in future.
Rendering a full <ul> for options is fine here, but consider extracting it into a reusable component for better modularity, especially if multiple dropdowns exist.

admin/form-builder/assets/js/components/form-taxonomy/template.php (1)

21-21: Multiple select usage and styling.
The application of builder_class_names('select') for a multiselect is a good approach. Verify that the class generator handles multi-select-specific needs such as adequate spacing and correct placeholder styling.

admin/form-builder/assets/js/components/form-radio_field/template.php (1)

2-17: Ensure Proper Input Binding for Radios
Currently, the <input> elements lack explicit Vue bindings for :value or v-model. Instead, the label elements control the radio state with :value and :checked. While this can work, it’s more common to bind these attributes on the <input> for clarity and maintainability. Consider moving the bindings to the <input> if you encounter future issues with radio group state.

admin/form-builder/assets/js/mixins/option-field.js (1)

9-9: Vue Defaults Must Return Objects
Switching from an empty object to a factory function returning { key: 'value' } is the correct approach in Vue to avoid shared state across instances. However, consider if 'key' and 'value' are truly meaningful defaults or simply placeholders. This might cause confusion if these fields are never replaced.

Also applies to: 14-14

admin/form-builder/assets/js/mixins/add-form-field.js (1)

49-54: Centralize or Reuse Button Classes
Defining action_button_classes as a computed property fosters consistency. If more buttons share these classes across the codebase, consider extracting them to a dedicated common styling solution so updates can be made in one place.

admin/form-builder/assets/js/components/field-options/template.php (2)

9-15: Consider adding accessibility attributes for toggle headings
The toggle headings (show_basic_settings) work well, but adding ARIA attributes such as aria-expanded and aria-controls could improve accessibility for screen readers and keyboard users.

Example improvement:

 <h3
     :class="show_basic_settings ? 'wpuf-text-green-600' : 'wpuf-text-gray-500'"
     class="wpuf-flex wpuf-mt-0 wpuf-mb-6 wpuf-justify-between hover:wpuf-cursor-pointer wpuf-text-sm"
     @click="show_basic_settings = !show_basic_settings"
+    :aria-expanded="show_basic_settings"
+    aria-controls="basic-settings-section"
 >
     {{ form_field_type_title }}
     <i :class="show_basic_settings ? 'fa fa-angle-down wpuf-text-green-600' : 'fa fa-angle-right wpuf-text-gray-500'"></i>
 </h3>

 <transition name="slide-fade">
-    <div v-show="show_basic_settings" class="option-field-section-fields">
+    <div
+        v-show="show_basic_settings"
+        class="option-field-section-fields"
+        id="basic-settings-section"
+    >
         ...
     </div>
 </transition>

32-37: Apply the same accessibility improvements for advanced settings
The advanced settings heading mirrors the basic settings toggler. For consistency and improved accessibility, add the same ARIA attributes.

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

36-70: Consider consolidating repeated class logic
The builder_class_names method enumerates multiple input types, returning a large switch statement. For maintainability, consider storing each type’s classes in a dictionary, which can simplify updates:

Example approach:

 builder_class_names: function(type_class) {
-    var commonClasses = '';
-    switch (type_class) {
-        case 'text':
-        case 'textfield':
-        case 'number':
-        ...
-            commonClasses = 'wpuf-block wpuf-min-w-full ...';
-            break;
-        ...
-    }
+    const mapClasses = {
+        text: 'wpuf-block wpuf-min-w-full ...', // etc.
+        textfield: 'wpuf-block wpuf-min-w-full ...',
+        number: 'wpuf-block wpuf-min-w-full ...',
+        upload_btn: 'file-selector  wpuf-rounded-md wpuf-btn-secondary',
+        radio: 'wpuf-ml-3 wpuf-block wpuf-text-sm ...',
+        ...
+    };
+
+    const commonClasses = mapClasses[type_class] || '';
 
     return [
         type_class,
         this.required_class(),
         'wpuf_' + this.field.name + '_' + this.form_id,
         commonClasses
     ];
 }
admin/form-builder/assets/js/components/field-visibility/template.php (2)

41-41: Typographical fix
“condiotional-logic-container” appears to be misspelled. Consider renaming to “conditional-logic-container” for clarity.

-<div v-if="'logged_in' === selected" class="condiotional-logic-container wpuf-mt-2">
+<div v-if="'logged_in' === selected" class="conditional-logic-container wpuf-mt-2">

60-60: Repeated typographical fix
Reuse the corrected spelling “conditional-logic-container” here as well.

-<div v-if="'subscribed_users' === selected" class="condiotional-logic-container wpuf-mt-2">
+<div v-if="'subscribed_users' === selected" class="conditional-logic-container wpuf-mt-2">
admin/form-builder/assets/js/components/field-option-data/template.php (2)

2-5: Improve labeling clarity for the top-level title.
The current label and help text synergy is good. However, consider ensuring screen readers can associate each label with the relevant input for improved accessibility.


23-35: Grid layout improvements.
Using wpuf-grid wpuf-grid-cols-4 for the options is valid. Make sure that, on small screens, the layout remains usable and responsive.

includes/Fields/Form_Field_Cloudflare_Turnstile.php (1)

41-48: Wrap Turnstile in <li> for consistent markup.
This <li> wrapper and additional wpuf-fields class keep styling consistent with other fields. Verify that any CSS or JS scripts that previously targeted the direct <div> are updated to handle the new structure.

admin/form-builder/assets/js/components/builder-stage-v4-1/index.js (4)

113-132: Consider removing unnecessary aliasing of this.
You set var self = this; at line 114, but you’re already using an arrow function in the then block. Arrow functions do not redefine this, so referencing this directly is sufficient:

 delete_field: function(index) {
-    var self = this;
     (Swal.fire({
-        text: self.i18n.delete_field_warn_msg,
+        text: this.i18n.delete_field_warn_msg,
         ...
     })).then((result) => {
-        if (result.isConfirmed) {
-            self.$store.commit('delete_form_field_element', index);
+        if (result.isConfirmed) {
+            this.$store.commit('delete_form_field_element', index);
         }
     });
 },
🧰 Tools
🪛 Biome (1.9.4)

[error] 114-114: This aliasing of this is unnecessary.

Arrow functions inherits this from their enclosing scope.
Safe fix: Use this instead of an alias.

(lint/complexity/noUselessThisAlias)


144-146: Simplify boolean return and consider optional chaining.
Line 145 uses a ternary to return a boolean. You can simplify:

- return (this.field_settings[template] && this.field_settings[template].pro_feature) ? true : false;
+ return !!(this.field_settings[template]?.pro_feature);
🧰 Tools
🪛 Biome (1.9.4)

[error] 145-145: Unnecessary use of boolean literals in conditional expression.

Simplify your code by directly assigning the result without using a ternary operator.
If your goal is negation, you may use the logical NOT (!) or double NOT (!!) operator for clearer and concise code.
Check for more details about NOT operator.
Unsafe fix: Remove the conditional expression with

(lint/complexity/noUselessTernary)


[error] 145-145: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


167-173: Optional chaining could improve readability.
At line 168, you can use optional chaining to avoid a repeated && check. Example:

- if (this.field_settings[template] && this.field_settings[template].is_full_width) {
+ if (this.field_settings[template]?.is_full_width) {
🧰 Tools
🪛 Biome (1.9.4)

[error] 168-168: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


175-177: Avoid unnecessary boolean literals in ternary.
At line 176, you can return the conditional directly:

- return ( field.recaptcha_type && 'invisible_recaptcha' === field.recaptcha_type ) ? true : false;
+ return field.recaptcha_type === 'invisible_recaptcha';
🧰 Tools
🪛 Biome (1.9.4)

[error] 176-176: Unnecessary use of boolean literals in conditional expression.

Simplify your code by directly assigning the result without using a ternary operator.
If your goal is negation, you may use the logical NOT (!) or double NOT (!!) operator for clearer and concise code.
Check for more details about NOT operator.
Unsafe fix: Remove the conditional expression with

(lint/complexity/noUselessTernary)

admin/form-builder/assets/js/components/form-fields-v4-1/template.php (1)

35-108: Dynamic field sections are nicely implemented.
The toggling mechanism, templates, and separate cases for pro/invalid/regular fields enhance control and clarity. Check if you need ARIA roles or labels for improved accessibility.

includes/Admin/Forms/Admin_Form_Builder.php (2)

129-129: Maintain alphabetical consistency if needed.

The 'recaptcha' field was appended at line 129. If there's a strict field ordering convention (alphabetical, usage, etc.), ensure consistency throughout the list.


264-275: Consider a filter or hook for advanced templating.

You introduced conditional logic to include either form-builder.php or form-builder-v4.1.php. A filter or an action might further empower developers to override or extend this selection for custom builder versions.

admin/form-builder/assets/js/components/form-column_field/index.js (1)

56-56: Maintain consistent data references.

Using $(this).parent().data('column') ensures clarity when identifying the drop target, but confirm that no other drag-and-drop functionalities rely on the previous approach. If so, update them consistently.

admin/form-builder/assets/js/components/builder-stage-v4-1/template.php (2)

60-61: Hover-based controls.

Using hover states to handle button opacity can declutter the UI but might obscure discoverability for new users. If user testing reveals confusion, consider a tooltip or a minimal indicator.


116-117: Pro feature link consistency.

Rendering a call-to-action for Pro-only features is consistent with the rest of the code. Double-check that the link matches your official marketing or promotional strategy.

includes/Admin/Posting.php (1)

32-39: Enhance the docblock with correct version tagging.

The docblock for dequeue_assets references @since WPUF_SINCE. It would be clearer to replace WPUF_SINCE with the actual plugin version (e.g., @since 4.2.0), ensuring proper tracking of when this method was introduced.

- * @since WPUF_SINCE
+ * @since 4.2.0
includes/Fields/Field_Contract.php (1)

68-72: Consider input validation for content restriction.

The new content_restriction field is typed as 'text', but presumably should be numeric if it represents characters or words. Validate or sanitize numeric input to avoid misuse or confusion.

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

188-369: Avoid repeating similar logic across builder components.

You introduced builder-stage-v4-1 as a clone of an existing component. Consider refactoring shared logic into a base or mixin to avoid duplicating code.

🧰 Tools
🪛 Biome (1.9.4)

[error] 332-332: Unnecessary use of boolean literals in conditional expression.

Simplify your code by directly assigning the result without using a ternary operator.
If your goal is negation, you may use the logical NOT (!) or double NOT (!!) operator for clearer and concise code.
Check for more details about NOT operator.
Unsafe fix: Remove the conditional expression with

(lint/complexity/noUselessTernary)


[error] 332-332: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 355-355: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 363-363: Unnecessary use of boolean literals in conditional expression.

Simplify your code by directly assigning the result without using a ternary operator.
If your goal is negation, you may use the logical NOT (!) or double NOT (!!) operator for clearer and concise code.
Check for more details about NOT operator.
Unsafe fix: Remove the conditional expression with

(lint/complexity/noUselessTernary)


[error] 301-301: This aliasing of this is unnecessary.

Arrow functions inherits this from their enclosing scope.
Safe fix: Use this instead of an alias.

(lint/complexity/noUselessThisAlias)


301-301: Remove unnecessary 'self' alias in arrow functions.

In modern JavaScript, arrow functions inherit this, so var self = this; is not needed.

-delete_field: function(index) {
-    var self = this;
-    (Swal.fire({
+delete_field: function(index) {
     (Swal.fire({
🧰 Tools
🪛 Biome (1.9.4)

[error] 301-301: This aliasing of this is unnecessary.

Arrow functions inherits this from their enclosing scope.
Safe fix: Use this instead of an alias.

(lint/complexity/noUselessThisAlias)


332-332: Simplify the boolean ternary.

The expression can be simplified by directly negating or double-banging the condition.

-return (this.field_settings[template] && this.field_settings[template].pro_feature) ? true : false;
+return !!(this.field_settings[template]?.pro_feature);
🧰 Tools
🪛 Biome (1.9.4)

[error] 332-332: Unnecessary use of boolean literals in conditional expression.

Simplify your code by directly assigning the result without using a ternary operator.
If your goal is negation, you may use the logical NOT (!) or double NOT (!!) operator for clearer and concise code.
Check for more details about NOT operator.
Unsafe fix: Remove the conditional expression with

(lint/complexity/noUselessTernary)


[error] 332-332: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


355-355: Use optional chaining for safer property access.

You can leverage optional chaining to safely access nested properties without additional checks.

-if (this.field_settings[template] && this.field_settings[template].is_full_width) {
+if (this.field_settings[template]?.is_full_width) {
🧰 Tools
🪛 Biome (1.9.4)

[error] 355-355: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


363-363: Eliminate the explicit boolean ternary.

Use a more direct approach to return a boolean.

-return ( field.recaptcha_type && 'invisible_recaptcha' === field.recaptcha_type ) ? true : false;
+return field.recaptcha_type === 'invisible_recaptcha';
🧰 Tools
🪛 Biome (1.9.4)

[error] 363-363: Unnecessary use of boolean literals in conditional expression.

Simplify your code by directly assigning the result without using a ternary operator.
If your goal is negation, you may use the logical NOT (!) or double NOT (!!) operator for clearer and concise code.
Check for more details about NOT operator.
Unsafe fix: Remove the conditional expression with

(lint/complexity/noUselessTernary)


777-782: Consider a user-friendly default for "Select an option".

When opening/hiding the dropdown, you might want to localize or adapt the default text ('Select an option') to the plugin’s language domain.


2020-2023: Tooltip placement improvement.

Replacing 'placement: 'auto top' with user-defined or dynamic placement can increase the tooltip usability for different screen sizes.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9801b41 and b06bc5c.

⛔ Files ignored due to path filters (43)
  • assets/images/adjustments-horizontal.svg is excluded by !**/*.svg
  • assets/images/arrow-up-tray.svg is excluded by !**/*.svg
  • assets/images/badge-check.svg is excluded by !**/*.svg
  • assets/images/check-circle.svg is excluded by !**/*.svg
  • assets/images/chevron-down.svg is excluded by !**/*.svg
  • assets/images/clock.svg is excluded by !**/*.svg
  • assets/images/cloud.svg is excluded by !**/*.svg
  • assets/images/code-bracket-square.svg is excluded by !**/*.svg
  • assets/images/code.svg is excluded by !**/*.svg
  • assets/images/command-line.svg is excluded by !**/*.svg
  • assets/images/document-check.svg is excluded by !**/*.svg
  • assets/images/exclamation-circle.svg is excluded by !**/*.svg
  • assets/images/eye-off.svg is excluded by !**/*.svg
  • assets/images/form-blank-state.svg is excluded by !**/*.svg
  • assets/images/globe-alt.svg is excluded by !**/*.svg
  • assets/images/link.svg is excluded by !**/*.svg
  • assets/images/location-marker.svg is excluded by !**/*.svg
  • assets/images/mail.svg is excluded by !**/*.svg
  • assets/images/map.svg is excluded by !**/*.svg
  • assets/images/menu-alt-2.svg is excluded by !**/*.svg
  • assets/images/menu-alt-4.svg is excluded by !**/*.svg
  • assets/images/photograph.svg is excluded by !**/*.svg
  • assets/images/play.svg is excluded by !**/*.svg
  • assets/images/qrcode.svg is excluded by !**/*.svg
  • assets/images/queue-list.svg is excluded by !**/*.svg
  • assets/images/recaptcha-placeholder.png is excluded by !**/*.png
  • assets/images/rectangle-stack.svg is excluded by !**/*.svg
  • assets/images/squares-2x2.svg is excluded by !**/*.svg
  • assets/images/squares-2x2.zip is excluded by !**/*.zip
  • assets/images/star.svg is excluded by !**/*.svg
  • assets/images/stop.svg is excluded by !**/*.svg
  • assets/images/tag.svg is excluded by !**/*.svg
  • assets/images/templates/blank.svg is excluded by !**/*.svg
  • assets/images/templates/edd.png is excluded by !**/*.png
  • assets/images/templates/edd.svg is excluded by !**/*.svg
  • assets/images/templates/event.svg is excluded by !**/*.svg
  • assets/images/templates/post.png is excluded by !**/*.png
  • assets/images/templates/post.svg is excluded by !**/*.svg
  • assets/images/templates/woocommerce.png is excluded by !**/*.png
  • assets/images/templates/woocommerce.svg is excluded by !**/*.svg
  • assets/images/title.svg is excluded by !**/*.svg
  • assets/images/view-columns.svg is excluded by !**/*.svg
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (82)
  • Gruntfile.js (5 hunks)
  • Lib/Appsero/Client.php (1 hunks)
  • admin/form-builder/assets/js/components/builder-stage-v4-1/index.js (1 hunks)
  • admin/form-builder/assets/js/components/builder-stage-v4-1/template.php (1 hunks)
  • admin/form-builder/assets/js/components/builder-stage/index.js (0 hunks)
  • admin/form-builder/assets/js/components/field-checkbox/index.js (1 hunks)
  • admin/form-builder/assets/js/components/field-checkbox/template.php (1 hunks)
  • admin/form-builder/assets/js/components/field-multiselect/template.php (1 hunks)
  • admin/form-builder/assets/js/components/field-option-data/index.js (1 hunks)
  • admin/form-builder/assets/js/components/field-option-data/template.php (1 hunks)
  • admin/form-builder/assets/js/components/field-option-pro-feature-alert/template.php (1 hunks)
  • admin/form-builder/assets/js/components/field-options/index.js (1 hunks)
  • admin/form-builder/assets/js/components/field-options/template.php (2 hunks)
  • admin/form-builder/assets/js/components/field-radio/template.php (1 hunks)
  • admin/form-builder/assets/js/components/field-select/index.js (2 hunks)
  • admin/form-builder/assets/js/components/field-select/template.php (1 hunks)
  • admin/form-builder/assets/js/components/field-text-meta/template.php (1 hunks)
  • admin/form-builder/assets/js/components/field-text/index.js (1 hunks)
  • admin/form-builder/assets/js/components/field-text/template.php (1 hunks)
  • admin/form-builder/assets/js/components/field-textarea/index.js (1 hunks)
  • admin/form-builder/assets/js/components/field-textarea/template.php (1 hunks)
  • admin/form-builder/assets/js/components/field-visibility/index.js (1 hunks)
  • admin/form-builder/assets/js/components/field-visibility/template.php (3 hunks)
  • admin/form-builder/assets/js/components/form-checkbox_field/template.php (1 hunks)
  • admin/form-builder/assets/js/components/form-column_field/index.js (3 hunks)
  • admin/form-builder/assets/js/components/form-column_field/template.php (1 hunks)
  • admin/form-builder/assets/js/components/form-custom_hidden_field/template.php (1 hunks)
  • admin/form-builder/assets/js/components/form-dropdown_field/template.php (1 hunks)
  • admin/form-builder/assets/js/components/form-email_address/template.php (1 hunks)
  • admin/form-builder/assets/js/components/form-featured_image/template.php (1 hunks)
  • admin/form-builder/assets/js/components/form-fields-v4-1/index.js (1 hunks)
  • admin/form-builder/assets/js/components/form-fields-v4-1/template.php (1 hunks)
  • admin/form-builder/assets/js/components/form-image_upload/template.php (1 hunks)
  • admin/form-builder/assets/js/components/form-multiple_select/template.php (1 hunks)
  • admin/form-builder/assets/js/components/form-post_content/template.php (1 hunks)
  • admin/form-builder/assets/js/components/form-post_excerpt/template.php (1 hunks)
  • admin/form-builder/assets/js/components/form-post_tags/template.php (1 hunks)
  • admin/form-builder/assets/js/components/form-post_title/template.php (1 hunks)
  • admin/form-builder/assets/js/components/form-radio_field/template.php (1 hunks)
  • admin/form-builder/assets/js/components/form-recaptcha/template.php (1 hunks)
  • admin/form-builder/assets/js/components/form-section_break/template.php (1 hunks)
  • admin/form-builder/assets/js/components/form-taxonomy/template.php (3 hunks)
  • admin/form-builder/assets/js/components/form-text_field/template.php (1 hunks)
  • admin/form-builder/assets/js/components/form-textarea_field/template.php (1 hunks)
  • admin/form-builder/assets/js/components/form-website_url/template.php (1 hunks)
  • admin/form-builder/assets/js/components/help-text/index.js (1 hunks)
  • admin/form-builder/assets/js/components/help-text/template.php (1 hunks)
  • admin/form-builder/assets/js/form-builder.js (13 hunks)
  • admin/form-builder/assets/js/mixins/add-form-field.js (1 hunks)
  • admin/form-builder/assets/js/mixins/form-field.js (3 hunks)
  • admin/form-builder/assets/js/mixins/option-field.js (1 hunks)
  • admin/form-builder/assets/less/form-builder.less (0 hunks)
  • admin/form-builder/views/form-builder-v4.1.php (1 hunks)
  • admin/form-builder/views/form-builder.php (2 hunks)
  • assets/css/admin.css (0 hunks)
  • assets/css/frontend-forms.css (1 hunks)
  • assets/js-templates/form-components.php (16 hunks)
  • assets/js/wpuf-form-builder-components.js (12 hunks)
  • assets/js/wpuf-form-builder-mixins.js (5 hunks)
  • assets/js/wpuf-form-builder.js (13 hunks)
  • assets/less/admin.less (0 hunks)
  • assets/less/frontend-forms.less (1 hunks)
  • includes/Admin/Admin_Subscription.php (1 hunks)
  • includes/Admin/Forms/Admin_Form.php (4 hunks)
  • includes/Admin/Forms/Admin_Form_Builder.php (4 hunks)
  • includes/Admin/Forms/Post/Templates/Form_Template.php (3 hunks)
  • includes/Admin/Forms/Post/Templates/Post_Form_Template_Events_Calendar.php (1 hunks)
  • includes/Admin/Forms/Post/Templates/Post_Form_Template_Post.php (1 hunks)
  • includes/Admin/Forms/Post/Templates/Post_Form_Template_WooCommerce.php (1 hunks)
  • includes/Admin/Forms/Post/Templates/Pro_Form_Preview_EDD.php (1 hunks)
  • includes/Admin/Forms/Template_Post.php (1 hunks)
  • includes/Admin/Menu.php (1 hunks)
  • includes/Admin/Posting.php (2 hunks)
  • includes/Admin/template-parts/modal-v4.1.php (1 hunks)
  • includes/Admin/template-parts/modal.php (5 hunks)
  • includes/Admin/views/post-form.php (1 hunks)
  • includes/Assets.php (1 hunks)
  • includes/Fields/Field_Contract.php (2 hunks)
  • includes/Fields/Form_Field_Checkbox.php (1 hunks)
  • includes/Fields/Form_Field_Cloudflare_Turnstile.php (1 hunks)
  • includes/Fields/Form_Field_Column.php (2 hunks)
  • includes/Fields/Form_Field_Dropdown.php (1 hunks)
⛔ Files not processed due to max files limit (26)
  • includes/Fields/Form_Field_Email.php
  • includes/Fields/Form_Field_Featured_Image.php
  • includes/Fields/Form_Field_Hidden.php
  • includes/Fields/Form_Field_Image.php
  • includes/Fields/Form_Field_MultiDropdown.php
  • includes/Fields/Form_Field_Numeric.php
  • includes/Fields/Form_Field_Post_Content.php
  • includes/Fields/Form_Field_Post_Excerpt.php
  • includes/Fields/Form_Field_Post_Tags.php
  • includes/Fields/Form_Field_Post_Taxonomy.php
  • includes/Fields/Form_Field_Post_Title.php
  • includes/Fields/Form_Field_Radio.php
  • includes/Fields/Form_Field_SectionBreak.php
  • includes/Fields/Form_Field_Text.php
  • includes/Fields/Form_Field_Textarea.php
  • includes/Fields/Form_Field_reCaptcha.php
  • includes/Fields/Form_Pro_Upgrade_Fields.php
  • includes/Frontend_Render_Form.php
  • includes/Pro_Upgrades.php
  • includes/Setup_Wizard.php
  • languages/wp-user-frontend.pot
  • package.json
  • src/css/admin/form-builder.css
  • tailwind.config.js
  • tests/chrome_recordings/post form templates.json
  • wpuf-functions.php
💤 Files with no reviewable changes (4)
  • admin/form-builder/assets/js/components/builder-stage/index.js
  • assets/css/admin.css
  • admin/form-builder/assets/less/form-builder.less
  • assets/less/admin.less
✅ Files skipped from review due to trivial changes (10)
  • includes/Fields/Form_Field_Checkbox.php
  • includes/Admin/Forms/Post/Templates/Post_Form_Template_Post.php
  • includes/Fields/Form_Field_Dropdown.php
  • admin/form-builder/assets/js/components/help-text/template.php
  • admin/form-builder/assets/js/components/form-multiple_select/template.php
  • includes/Admin/Forms/Post/Templates/Post_Form_Template_WooCommerce.php
  • includes/Admin/Forms/Post/Templates/Post_Form_Template_Events_Calendar.php
  • includes/Admin/template-parts/modal.php
  • includes/Admin/Forms/Template_Post.php
  • includes/Assets.php
🧰 Additional context used
🪛 Biome (1.9.4)
assets/js/wpuf-form-builder.js

[error] 530-530: Shouldn't redeclare 'settings_tabs'. Consider to delete it or rename it.

'settings_tabs' is defined here:

(lint/suspicious/noRedeclare)


[error] 538-538: Shouldn't redeclare 'clipboard'. Consider to delete it or rename it.

'clipboard' is defined here:

(lint/suspicious/noRedeclare)


[error] 541-541: Shouldn't redeclare 'self'. Consider to delete it or rename it.

'self' is defined here:

(lint/suspicious/noRedeclare)

admin/form-builder/assets/js/components/builder-stage-v4-1/index.js

[error] 145-145: Unnecessary use of boolean literals in conditional expression.

Simplify your code by directly assigning the result without using a ternary operator.
If your goal is negation, you may use the logical NOT (!) or double NOT (!!) operator for clearer and concise code.
Check for more details about NOT operator.
Unsafe fix: Remove the conditional expression with

(lint/complexity/noUselessTernary)


[error] 145-145: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 168-168: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 176-176: Unnecessary use of boolean literals in conditional expression.

Simplify your code by directly assigning the result without using a ternary operator.
If your goal is negation, you may use the logical NOT (!) or double NOT (!!) operator for clearer and concise code.
Check for more details about NOT operator.
Unsafe fix: Remove the conditional expression with

(lint/complexity/noUselessTernary)


[error] 114-114: This aliasing of this is unnecessary.

Arrow functions inherits this from their enclosing scope.
Safe fix: Use this instead of an alias.

(lint/complexity/noUselessThisAlias)

admin/form-builder/assets/js/components/form-fields-v4-1/index.js

[error] 71-71: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 94-94: This aliasing of this is unnecessary.

Arrow functions inherits this from their enclosing scope.
Safe fix: Use this instead of an alias.

(lint/complexity/noUselessThisAlias)

assets/js/wpuf-form-builder-components.js

[error] 332-332: Unnecessary use of boolean literals in conditional expression.

Simplify your code by directly assigning the result without using a ternary operator.
If your goal is negation, you may use the logical NOT (!) or double NOT (!!) operator for clearer and concise code.
Check for more details about NOT operator.
Unsafe fix: Remove the conditional expression with

(lint/complexity/noUselessTernary)


[error] 332-332: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 355-355: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 363-363: Unnecessary use of boolean literals in conditional expression.

Simplify your code by directly assigning the result without using a ternary operator.
If your goal is negation, you may use the logical NOT (!) or double NOT (!!) operator for clearer and concise code.
Check for more details about NOT operator.
Unsafe fix: Remove the conditional expression with

(lint/complexity/noUselessTernary)


[error] 301-301: This aliasing of this is unnecessary.

Arrow functions inherits this from their enclosing scope.
Safe fix: Use this instead of an alias.

(lint/complexity/noUselessThisAlias)


[error] 1618-1618: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 1641-1641: This aliasing of this is unnecessary.

Arrow functions inherits this from their enclosing scope.
Safe fix: Use this instead of an alias.

(lint/complexity/noUselessThisAlias)

admin/form-builder/assets/js/form-builder.js

[error] 530-530: Shouldn't redeclare 'settings_tabs'. Consider to delete it or rename it.

'settings_tabs' is defined here:

(lint/suspicious/noRedeclare)


[error] 538-538: Shouldn't redeclare 'clipboard'. Consider to delete it or rename it.

'clipboard' is defined here:

(lint/suspicious/noRedeclare)


[error] 541-541: Shouldn't redeclare 'self'. Consider to delete it or rename it.

'self' is defined here:

(lint/suspicious/noRedeclare)

🔇 Additional comments (160)
admin/form-builder/assets/js/components/form-textarea_field/template.php (3)

5-5: Great fix for the default binding.

Previously, the binding might have been incorrectly spelled. Using :default="field.default" ensures proper access and reactivity for the default value.


11-14: Conditional rendering logic looks sound.

The v-if="'no' !== field.rich" properly displays the <text-editor> only when rich text editing is enabled. Make sure to cover both scenarios in your tests (rich text on and off).


16-16: Semantic update from span to p for help text.

Using a paragraph element (<p>) enhances readability and consistency with typical block-level text semantics at no functional cost.

assets/less/frontend-forms.less (1)

259-259: LGTM: Border removal improves visual cleanliness

The removal of the border from .wp-editor-wrap aligns with modern UI practices and creates a cleaner interface.

assets/css/frontend-forms.css (1)

Line range hint 1-1000: Generated file looks good

This is an automatically generated CSS file from the LESS source. No issues found in the compilation output.

includes/Admin/Forms/Post/Templates/Form_Template.php (2)

19-19: Revisit commented-out code or remove it entirely.
By commenting out the admin_footer action, you’re losing the chance to render post form templates directly in the footer. Evaluate whether this is still needed. If it is deprecated, consider removing it altogether to keep the codebase clean.


112-118: Ensure correct file inclusion for modal template.
The new version-based approach for including the modal template is fine, but verify that the file paths indeed exist and that the correct modal is used for each version. You might also add a fallback for unexpected scenarios.

includes/Admin/Forms/Post/Templates/Pro_Form_Preview_EDD.php (1)

30-30: Switching from PNG to SVG is a great scalability improvement.

This update ensures better resolution independence and smaller file sizes. However, confirm that the new asset file edd.svg is present in the assets directory and properly referenced.

You can verify the presence of the SVG file using the following script:

✅ Verification successful

SVG file is correctly placed and referenced

The verification confirms that edd.svg exists at assets/images/templates/edd.svg, which matches the path referenced in the code through WPUF_ASSET_URI . '/images/templates/edd.svg'. The asset is properly placed in the expected directory structure.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Searching for the file 'edd.svg' in the repository
fd 'edd.svg'

Length of output: 44

admin/form-builder/assets/js/components/field-options/index.js (1)

7-7: Ensure proper integration of the new mixin

Adding wpuf_mixins.form_field_mixin is a good step toward a more unified approach to managing form fields. Please make sure this mixin does not introduce conflicting reactive properties or methods that may override the existing functionality from wpuf_mixins.field_options.

Run the following script to search for potential naming collisions (e.g., methods, computed properties, watchers) across mixin definitions:

✅ Verification successful

Let me gather more information about the mixin definitions to check for potential conflicts.


Let me gather information about the field_options mixin to complete the analysis.


Let me try a different approach to find the field_options mixin definition.


Let me try one more search to find the field_options mixin definition.


Based on the analysis of the codebase, I can now provide a definitive response about the mixin integration.

No conflicts found between the mixins

The wpuf_mixins.form_field_mixin and wpuf_mixins.field_options appear to be properly integrated without any naming collisions. The form_field_mixin provides basic form field functionality with:

  • Props: field object
  • Computed properties: form_id, has_options
  • Methods: class_names, builder_class_names, required_class, is_selected

The field_options mixin appears to be used for field option panel functionality and doesn't show any overlapping method or property names with form_field_mixin.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Search for potential naming collisions between mixin definitions.

# We'll search for definitions in both mixins and compare method/computed property names
rg "computed:|methods:|watch:|props:" -A 20 | grep -E "wpuf_mixins.field_options|wpuf_mixins.form_field_mixin"

Length of output: 613


Script:

#!/bin/bash
# Search for the mixin definitions and their contents
ast-grep --pattern 'wpuf_mixins.field_options = {
  $$$
}'

ast-grep --pattern 'wpuf_mixins.form_field_mixin = {
  $$$
}'

Length of output: 13486


Script:

#!/bin/bash
# Search for the field_options mixin definition
ast-grep --pattern 'wpuf_mixins.field_options = {
  $$$
}'

# Also search for any direct references to field_options methods
rg "field_options\." -A 3

Length of output: 88


Script:

#!/bin/bash
# Search for files that might contain the field_options mixin definition
fd -e js | xargs rg "wpuf_mixins.field_options\s*=" -A 10

# Also search for the file that might contain the mixin definitions
fd "wpuf-form-builder-mixins.js" -x cat

Length of output: 11008


Script:

#!/bin/bash
# Search for field_options in all JavaScript files
rg -l "field_options" | xargs cat

# Also try to find any potential conflicts in method names
rg "methods:|computed:" -A 2 admin/form-builder/assets/js/

Length of output: 82459

includes/Admin/Menu.php (1)

133-133: Review the required file location

The path to modal-v4.1.php is loaded via WPUF_ROOT. Verify that this file exists and is accessible across all environments.

✅ Verification successful

File exists at the expected location

The file modal-v4.1.php exists at the correct path includes/Admin/template-parts/modal-v4.1.php relative to the repository root, which aligns with the path being loaded via WPUF_ROOT. The file is accessible with proper read permissions (644).

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify that the template-parts/modal-v4.1.php file exists.

fd modal-v4.1.php --exec ls -lah

Length of output: 130

assets/js/wpuf-form-builder-mixins.js (4)

68-68: Great improvement using a factory function for the default prop.

Defining the default as a function returning a new object is a best practice in Vue. This prevents shared references across component instances and avoids unexpected mutations.


83-83: Closing brace inclusion looks correct.

The syntax of the computed property has_options is now correct with the closing brace. This resolves any prior parsing issues.


311-311: Proper default for option_field prop.

Utilizing a function returning an object here follows Vue best practices, preventing shared mutable state across component instances.


316-316: Good use of a factory function for editing_form_field.

Same reasoning as above—this ensures each prop instance has its own unique data reference.

includes/Admin/template-parts/modal-v4.1.php (1)

100-115: Verify the safety of inline file reads
The code reads the crown icon file content directly from the file system (file_get_contents( $crown_icon )). Ensure $crown_icon always resolves to an expected local file path to prevent potential security risks if the path can be tampered with.

✅ Verification successful

Let me verify how $crown_icon is defined and used.


Let me try a different approach to find the definition and usage of $crown_icon.


Let me check how WPUF_ROOT is defined to ensure it's secure.


File reads are properly secured with hardcoded paths

The usage of file_get_contents($crown_icon) is safe because:

  1. $crown_icon is always defined as WPUF_ROOT . '/assets/images/crown.svg'
  2. WPUF_ROOT is defined in the main plugin file as __DIR__, which is a PHP magic constant that provides the directory path of the current file
  3. The file existence is properly checked with file_exists() before reading
  4. The SVG file is located at a fixed path within the plugin directory and cannot be manipulated by user input
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify that crown.svg is present in the expected location and is not user-controlled.
fd crown.svg

Length of output: 38


Script:

#!/bin/bash
# Find where $crown_icon is defined and how it's constructed
rg -B 2 -A 2 "\$crown_icon\s*="

Length of output: 32


Script:

#!/bin/bash
# Search for the file content around the crown icon usage
rg -B 10 -A 2 "file_exists\(\s*\\\$crown_icon\s*\)"

Length of output: 8374


Script:

#!/bin/bash
# Search for WPUF_ROOT definition
rg -B 2 -A 2 "WPUF_ROOT|define.*WPUF_ROOT"

Length of output: 21430

admin/form-builder/assets/js/components/form-fields-v4-1/index.js (9)

1-3: Consistent component documentation
The introductory comment block clearly describes the component.


7-8: Mixins usage
Combining multiple mixins (wpuf_form_builder_mixins and wpuf_mixins.add_form_field) is a good practice to keep the component logic organized.


9-14: Data properties provide clarity
Storing searched_fields and asset_url in data is straightforward and keeps dependencies explicit.


16-28: Computed properties
The computed properties effectively retrieve Vuex store data. No issues or performance concerns identified.


40-44: panel_toggle method
Straightforward use of a Vuex mutation to toggle the panel. No issues found.


45-47: is_pro_feature method
Relies on field_settings[field].pro_feature. This is fine if the store’s data is always guaranteed.


49-66: SweetAlert usage in alert_pro_feature
This is properly set up with a confirm button to open an external link. Implementation looks solid.


83-85: get_invalidate_btn_class functionality
Method retrieves a class from store data. This is straightforward and efficient.


87-89: set_default_panel_sections method
Resets panel sections using a store commit. No concerns here.

admin/form-builder/assets/js/components/form-column_field/template.php (4)

1-3: Readable utility classes
Using utility classes like wpuf-flex and wpuf-gap-4 enhances maintainability. Good approach for consistent styling.


5-8: Dynamic columns loop
The v-for loop with :key="column" is correct for rendering columns. Ensure each column in columnClasses is unique.


14-27: Column fields iteration
The multi-property usage (e.g., :class, data-source, v-for) is well-structured. Hover and grouping classes look correct for styling.


65-107: Action buttons
The control panel for editing, copying, and removing fields is clear. The conditionals for failed validation vs. normal usage are well-handled. No major issues spotted.

admin/form-builder/views/form-builder-v4.1.php (4)

1-4: Semantic form structure
Wrapping the builder in a <form> with @submit.prevent="save_form_builder" is clean and intuitive for capturing save events.


13-23: Editable form title
Toggling post_title_editing with icons is user-friendly. The computed visual states are handled by toggling classes. Nicely done.


89-107: Preview and Save button states
Using v-if="!is_form_saving" and the subsequent v-else to show a loader is a good example of reactive UI.


153-176: Tabbed interface
The usage of v-show="active_tab === 'form-editor'" and v-show="active_tab === 'form-settings'" is a straightforward approach to display different sections. This improves user experience clearly.

assets/js/wpuf-form-builder.js (7)

44-46: Flags for older form and post form
is_older_form and is_post_form help differentiate form types. Ensure consistent updates if additional form types appear.


73-73: Editing field reset
Conditionally resetting editing_field_id when switching panels is a neat approach to avoid residual states in the UI.


Line range hint 93-108: open_field_settings mutation
Filters the correct field from form_fields. The setTimeout ensures the panel transitions before setting the editing_field_id. This is a valid approach.


245-245: Adjust current_panel upon deletion
Switching back to 'form-fields-v4-1' or 'form-fields' after deleting a field prevents leftover state references.


397-399: set_panel_sections mutation
Assigns sections to state.panel_sections. Straightforward.


401-404: set_default_panel_sections mutation
Resets panel sections to the original wpuf_form_builder.panel_sections. Helpful for reverting.


423-428: New data properties
enableMultistep, shortcodeCopied, active_tab, and active_settings_tab add clarity for new UI features.

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

44-46: Flag usage
Defining is_older_form and is_post_form in state is consistent with the logic from the rest of the builder.


73-73: Panel reset
Resets editing_field_id correctly when toggling to a field list panel. Good to maintain consistency.


Line range hint 93-108: open_field_settings
Same pattern as seen elsewhere. Filtering the correct field ensures minimal overhead, and the setTimeout for transitions is practical.


245-245: Deleting field concurrency
Switching current_panel to 'form-fields-v4-1' or 'form-fields' helps avoid dangling references.


392-392: Deleting a column field
Similar logic to single-field deletion. Properly references is_older_form to revert the panel.


396-399: set_panel_sections
Straight assignment to store. Straightforward.


401-404: set_default_panel_sections
Pulling defaults from wpuf_form_builder.panel_sections is a tidy approach for easy resets.


423-428: Extended data properties
Storing isDirty, enableMultistep, shortcodeCopied, active_tab, and logoUrl in data is consistent with the updated form builder interface.

assets/js-templates/form-components.php (7)

93-205: Double-check accessibility and keyboard interactions
This entire block defines the main form structure and field controls. Although it looks visually appealing, ensure that drag-and-drop and other interactive elements are usable with a keyboard (focus states, ARIA attributes). Consider verifying it for screen-readers as well.


210-283: Hidden fields block
The hidden fields section is well-structured. The controls for editing, cloning, and removing hidden fields are consistent with other fields. This looks good.


285-294: Checkbox template checks
The <input type="checkbox"> loop is straightforward. Consider verifying that any newly introduced classes match your project’s BEM/utility guidelines for styling consistency.


327-435: Dynamic option data
This section handles dynamic addition/removal of options with checkboxes/radio input. Carefully watch for edge cases, such as when no options remain or when label/value contain special characters.


441-446: Pro feature alerts & field options
The “Pro Version” alert logic and the basic/advanced settings toggles look consistent. Make sure that external links open in new tabs (target="_blank") and that the user is not trapped post-navigation (add rel="noopener" if needed for security).

Also applies to: 452-488


512-548: Various field templates
All these field templates (radio, select, text, hidden, featured image, multiple select, post content/excerpt/tags/title, etc.) share a consistent layout pattern and styling approach. Continue ensuring that the new utility classes (wpuf-text-sm, wpuf-text-gray-500, etc.) are uniformly applied across the entire form builder. Also, confirm that HTML-escaped or sanitized outputs are used for user-generated content, particularly in help texts, to prevent any risk of XSS injection.

Also applies to: 573-596, 602-624, 629-641, 647-650, 656-693, 743-777, 929-934, 946-955, 963-968, 976-991, 1189-1189, 1208-1250


1162-1181: Remaining field partial templates
The updated image upload, radio-field, section-break, taxonomy, and other textual field components align with the approach used elsewhere. This maintains consistency. Everything seems properly introduced and integrated.

Also applies to: 1285-1317, 1335-1352, 1360-1402, 1413-1462

includes/Admin/views/post-form.php (1)

1-10: Conditional rendering of builder hooks
Switching between wpuf_admin_form_builder and wpuf_admin_form_builder_view based on the WPUF Pro version introduces new flexibility. Confirm it still meets backward compatibility requirements for older sites without WPUF_PRO_VERSION.

admin/form-builder/assets/js/components/form-website_url/template.php (1)

4-9: Consistent use of builder_class_names for URL inputs
Switching to builder_class_names('url') keeps styling consistent with other form elements. This looks good.

admin/form-builder/assets/js/components/form-text_field/template.php (1)

7-9: Refactored class binding and help text semantics
Using builder_class_names('textfield') aligns with the broader shift to utility-based classes. Displaying help text in a <p> element is more semantic. Good change.

admin/form-builder/assets/js/components/form-custom_hidden_field/template.php (1)

4-9: Hidden field styling improvements
Changing the class binding for the hidden field and updating help text to a <p> improves consistency and readability.

admin/form-builder/assets/js/components/form-email_address/template.php (1)

9-9: Good semantic improvement
Using a <p> element instead of a <span> for help text is more semantically appropriate for paragraph content, improves accessibility, and provides better structure for screen readers.

admin/form-builder/assets/js/components/field-textarea/template.php (1)

5-5: Dynamic class usage is consistent and flexible
Good use of builder_class_names('textareafield') for tailoring styles. It aligns with the plugin’s pattern of configurable classes for form fields.

admin/form-builder/assets/js/components/field-textarea/index.js (1)

5-6: Seamless mixin integration
Adding wpuf_mixins.form_field_mixin here leverages reusable functionality across form fields, promoting cleaner and more maintainable code.

admin/form-builder/assets/js/components/form-post_title/template.php (1)

7-8: Verify interaction between dynamic and static class attributes.
You have :class="class_names('textfield')" and a static class on the same element. Double-check that these do not conflict. In Vue, they are merged, but reviewing them for consistency helps avoid style overrides or unexpected results.

admin/form-builder/assets/js/components/form-post_tags/template.php (1)

4-5: Ensure builder_class_names usage is consistent.
Using :class="builder_class_names('text')" plus a static class is typically fine in Vue, but confirm that it doesn’t inadvertently override or duplicate computed classes.

admin/form-builder/assets/js/components/form-post_excerpt/template.php (1)

4-4: Confirm correct usage of builder_class_names.
This helper method is introduced to handle dynamic classes. Verify it merges well with any static classes or if you want to rely on a single approach for styling consistency.

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

1-1: Update looks good for conditional rendering.
Using v-if="met_dependencies" ensures the component does not render at all unless dependencies are met, which can improve performance and hide unneeded DOM elements.


8-8: Ensure consistent usage of Tailwind utility classes.
The newly added utility classes (wpuf-w-full wpuf-mt-2 wpuf-border-primary wpuf-z-30) appear consistent with the plugin’s styling approach. Consider verifying that these classes align well with any global design tokens or guidelines.


12-15: Confirm custom states styling.
The checked:wpuf-bg-primary class indicates a Tailwind variant for the checked state, which is not always natively supported for <option> elements. Verify that this class is effectively applied or recognized by your styling pipeline for multi-select options.

admin/form-builder/assets/js/components/field-checkbox/template.php (2)

1-1: Addition of margin utilities.
Using wpuf-mb-6 adds spacing between checkbox groups. This is a helpful design improvement, but ensure consistency with other form-field spacing.


6-6: Inline vs. stacked checkboxes.
class="wpuf-mt-2" for each list item enhances spacing. If multiple checkboxes need to be displayed inline, verify that option_field.inline is being handled properly to remove or override this top margin when desired.

admin/form-builder/assets/js/components/form-dropdown_field/template.php (1)

4-4: Leverage utility classes for cohesive design.
The addition of multiple utility classes (wpuf-text-gray-900, wpuf-rounded-md, etc.) systematically streamlines design. Consider highlighting these new classes in your documentation for consistent usage across components.

admin/form-builder/assets/js/components/field-text/index.js (1)

5-6: Include validation or compatibility checks for the new mixin.

Adding wpuf_mixins.form_field_mixin can introduce shared methods and computed properties beneficial for maintaining consistent behavior across multiple field types. However, ensure that any dependencies or validations in the form_field_mixin are satisfied by this component to prevent potential compatibility issues.

admin/form-builder/assets/js/components/field-text/template.php (1)

2-24: Review edge cases for field variations and ensure fallback UI.

The logic for rendering <input type="number"> or <input type="text"> covers two specific conditions, but if option_field.variation is defined yet not 'number', there might be a scenario where neither input is rendered. Consider a fallback or an else-case to handle any additional field variations or unexpected states. Additionally, the usage of builder_class_names('text') is a good approach for dynamically setting CSS classes.

admin/form-builder/assets/js/components/form-section_break/template.php (2)

1-8: Consistent use of conditional rendering for "regular" divider mode
The new layout correctly distinguishes the "regular" divider mode and applies the expected styling for the title, description, and border. This approach improves code clarity and layout consistency.


9-18: Well-structured dashed divider layout
Using wpuf-flex along with the border sections on each side of the title cleanly represents a dashed divider. This is an effective way to visually differentiate the two layout modes.

admin/form-builder/assets/js/components/field-checkbox/index.js (1)

5-6: Addition of form_field_mixin for enhanced reusability
Incorporating wpuf_mixins.form_field_mixin improves code reuse and consistency across form fields. This approach centralizes common logic, making it easier to maintain and extend component functionality.

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

2-4: Good use of strict equality for field.insert_image
Switching from loose equality to strict equality (=== 'yes') is a best practice that helps avoid unintended type coercions.


5-12: Successful integration of SVG icon in the upload button
Adding an SVG icon inside the button improves visual clarity. The dynamic class binding with builder_class_names('upload_btn') maintains styling consistency across components.


18-18: Clear distinction between rich and non-rich text areas
Using a conditional to determine rendering of text-editor vs. <textarea> helps provide a flexible editing experience appropriate to the field’s setting.

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

4-5: Uniform button styling with utility classes
The new classes (wpuf-inline-flex, wpuf-items-center, wpuf-gap-x-1.5) create consistent spacing and alignment for the button. Dynamic class binding also promotes a cohesive UI.


10-12: SVG icon enhances visual clarity
Including an inline SVG next to custom button text is an excellent step for improved discoverability. The new icon helps users identify the upload action.


19-19: Improved accessibility and semantics for help text
Replacing <span> with <p> and adding descriptive utility classes (wpuf-text-sm, etc.) makes the help text more noticeable and semantically correct.

admin/form-builder/assets/js/components/form-image_upload/template.php (1)

23-23: Help text styling is clear and consistent.
Switching from <span> to <p> for the help text with new classes can improve readability and consistency with the rest of the UI. No further change required.

admin/form-builder/assets/js/components/field-visibility/index.js (1)

5-6: Good addition of the form field mixin.
Incorporating wpuf_mixins.form_field_mixin unifies class handling and data management for form fields. This should reduce duplicated logic across components.

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

11-15: Maintain consistent icon usage.
The toggling of fa-angle-up and fa-angle-down is good. Ensure that the same icon library is used consistently in the rest of the form builder for a uniform user experience.


17-19: Ensure dropdown positioning in small screens.
Positioning across various devices is crucial. The wpuf-z-30 class is a good start, but confirm there's enough z-index to avoid overlay issues on mobile.


22-26: Update selected value consistently.
The inline handler @click="[value = key, showOptions = false, selectedOption = option]" is succinct, but ensure that local state is updated properly in sync with any Vuex store or higher-level parent component state if needed.

admin/form-builder/assets/js/components/form-taxonomy/template.php (4)

4-5: Dynamic classes for select elements appear correct.
Using builder_class_names('select') ensures consistent styling across multiple form fields. Keep verifying the returned class list.


10-12: Confirm uniform styling for nested selects.
The nested <select> using builder_class_names('select') might differ in styling from the top-level version. Ensure consistent UI across different taxonomy field types.


40-42: Dynamic placeholder and size attributes.
Well done dynamically binding placeholder and size. This is more flexible than a static approach.


46-46: Help text styling.
Replacing <span> with <p> and adding a consistent text style, as in other form components, keeps the UI uniform.

admin/form-builder/assets/js/components/form-radio_field/template.php (2)

19-32: Inline Radio Structure Looks Good
The inline radio layout is neatly done. This approach is consistent with modern UI patterns and helps maintain styling parity with the non-inline block above.


34-34: Consider Sanitizing HTML in Help Text
Using v-html can introduce security risks if the source data is not sanitized. Ensure field.help is safe or sanitized upstream to prevent potential XSS attacks.

admin/form-builder/assets/js/components/field-radio/template.php (2)

2-19: Well-Structured Radio Groups
The radio group logic and help-text display are clear. The code effectively handles met dependencies and nicely separates label and help text. Good job!


21-38: Inline Layout Implementation
Displaying the radio options inline is handled gracefully. The conditional margin class on the label (:class="index !== 0 ? 'wpuf-ml-2' : ''") is a nice touch to ensure spacing consistency.

admin/form-builder/assets/js/components/field-options/template.php (1)

1-1: Consistent use of utility classes
Adding the wpuf-px-6 class here enhances the horizontal padding, aligning it with other Tailwind-like utility classes in the codebase.

admin/form-builder/assets/js/mixins/form-field.js (2)

9-9: Preventing shared object references
Using a factory function for the default prop ensures a fresh object is returned each time, preventing accidental mutations across instances.


24-24: Syntactical correction
This closing brace correctly terminates the has_options computed property definition. No further changes required.

admin/form-builder/assets/js/components/field-visibility/template.php (5)

2-7: Usage of flex layout for title and help text
Switching to a flex-container here is a clean approach, allowing the label and help text to occupy separate spaces more naturally.


9-21: Radio group styling
The new layout and classes for the non-inline radio group look consistent and user-friendly. Ensure it aligns visually with other field types for uniform design.


23-39: Streamlined inline radio group
Using wpuf-flex and wpuf-flex-wrap for inline layout is consistent with the rest of the UI logic. This change is cohesive with the non-inline case above.


50-51: Consistent application of builder classes
Using :class="builder_class_names('checkbox')" unifies the styling for checkboxes consistently across the builder. This is a solid approach.


70-71: Subscription logic emergent
The subscription listing approach with checkboxes is consistent and straightforward. Continue verifying that the builder_class_names usage (if needed) is applied uniformly across these dynamic inputs.

admin/form-builder/assets/js/components/field-option-data/index.js (1)

9-10: Verify potential overlap of methods from multiple mixins
Adding wpuf_mixins.form_field_mixin alongside option_field_mixin is beneficial, but confirm no method name collisions or overshadowing occurs.

Use a script to search for identical method names among these mixins:

✅ Verification successful

Let me try a different approach to find the mixin methods.


After analyzing the mixin files, I can now provide a definitive response about potential method collisions between option_field_mixin and form_field_mixin.

No method name collisions found between the mixins

The analysis of both mixins shows they have distinct, non-overlapping methods:

  • option_field_mixin methods:

    • update_value()
  • form_field_mixin methods:

    • class_names()
    • builder_class_names()
    • required_class()
    • is_selected()

Each mixin serves a different purpose and their methods are uniquely named, so there's no risk of method overshadowing or collisions.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Searching for duplicate method names in mixins
ast-grep --pattern $'export default {
  methods: {
    $_() {}
  }
}' 

Length of output: 70


Script:

#!/bin/bash
# First, let's locate the mixin files
fd mixin -t f

# Then, let's examine their content
echo "=== Content of found mixin files ==="
fd mixin -t f -x cat {}

Length of output: 13755

Lib/Appsero/Client.php (1)

168-168: Ensure parameter usage aligns with WordPress best practices.
Changing the get_plugin_data call to ( $this->file, true, false ) sets $markup = true and $translate = false. This should be valid, but confirm you really do not want translation to occur for plugin headers, as translations will be bypassed.

Would you like a script to scan for references to translated plugin data to ensure consistency?

admin/form-builder/assets/js/components/field-option-data/template.php (2)

7-22: Validate the two checkbox states.
Both the “Show values” and “Sync values” checkboxes are placed close together, which is convenient. Ensure they do not conflict logically (e.g., the app can handle both states being true).


36-110: Optimize v-for list management and user actions.

  1. The v-for loop for adding, removing, and sorting items is correct; confirm you handle index references carefully when reordering.
  2. The “Delete” and “Add” buttons rely on an index-based approach. Confirm no data reactivity issues occur when arrays shrink or expand.

Would you like me to generate a test snippet that programmatically verifies these actions in different sequences (add multiple items, remove from the middle, reorder, etc.)?

includes/Fields/Form_Field_Column.php (2)

13-13: Icon name updated to view-columns.
Ensure this new icon reference exists in your icon set or library so it displays correctly.


83-83: Clarify maximum columns help text.
The updated text clarifies a maximum of 3 columns. Ensure your client-side validations (e.g., in the form builder) reflect the same constraint to avoid mismatches.

admin/form-builder/assets/js/components/builder-stage-v4-1/index.js (8)

1-2: New component registration looks good.
This new builder-stage-v4-1 component is well-structured and follows Vue’s component registration pattern.


4-4: Mixins usage is consistent.
Using the wpuf_form_builder_mixins and other mixins keeps the code DRY and modular.


6-28: Computed properties are clear.
They provide straightforward access to Vuex state, ensuring data is reactive.


30-82: Sortable initialization is properly placed in mounted.
The jQuery UI sortable instance effectively handles reordering. Verify if older browsers or Vue's reactivity might cause unexpected behaviors. Otherwise, looking good.


84-88: Function naming is intuitive.
open_field_settings succinctly reflects its functionality. Implementation is straightforward.


89-111: Cloning logic is correct.
The duplicate handling is clear, and the error feedback for single-instance fields is user-friendly.


134-142: delete_hidden_field method merges well with delete_field.
Looping to locate the matching hidden field is fine, though you could exit after deletion for efficiency.


179-182: Field naming retrieval is straightforward.
Ensures a uniform approach for retrieving the user-facing name of each field.

admin/form-builder/assets/js/components/form-fields-v4-1/template.php (1)

1-34: Search functionality and input design are well-structured.
The conditional icons for empty vs. non-empty search input provide straightforward user feedback.

admin/form-builder/views/form-builder.php (2)

42-42: Inline variable usage is consistent.
The $form_id usage here is straightforward and contextually relevant for copying the shortcode.


59-59: List styling for form switcher is user-friendly.
The extra classes .button.ui-draggable.ui-draggable-handle improve drag-and-drop interactions. Consider verifying cross-browser support.

Gruntfile.js (5)

2-6: Definition of tailwindFileMap extends build capabilities.
This approach is clean. Just ensure you keep it in sync with other relevant template or CSS paths as they expand.


119-133: New tailwind watch target is well-organized.
Monitors relevant files for changes and triggers the shell:tailwind task. This automated flow helps maintain consistent styling.


245-249: Tailwind shell command is clearly parameterized.
This pattern helps dynamically generate commands. Provides a future-proof approach for working with multiple input-output pairs.


279-283: Watch callback extends build pipeline logically.
Running 'tailwind' as part of the watch flow ensures styles remain updated in real-time.


285-301: Tailwind Grunt task is flexible and robust.
The iteration over tailwindFileMap is straightforward, verifying file existence before running the command. Good job.

includes/Admin/Forms/Admin_Form_Builder.php (4)

51-51: Good use of a new action hook.

Adding the wpuf_admin_form_builder_view action helps isolate and extend specific view logic for the form builder, enhancing flexibility for versioned templates.


166-166: Confirm the usage of root_dir.

'root_dir' => WPUF_ROOT, is localized. Verify that other parts of the code rely on this variable or if it might be unnecessary. Overexposing directory structures could pose security concerns if misused.


172-172: Version check logic looks good.

This conditionally sets is_older_form by comparing WPUF_PRO_VERSION. Ensure that all references to this flag within Vuex or other components gracefully handle false or undefined states if the constant is missing.


279-279: Documentation clarity improved.

The updated doc comment for the i18n method clarifies its purpose. This is helpful for contributors who consult inline documentation.

admin/form-builder/assets/js/components/form-column_field/index.js (4)

29-29: Selector refinement.

Changing the selector to ".wpuf-field-columns .wpuf-column-inner-fields" might affect any existing code or styles depending on the old selector. Ensure all references to the previous selector are updated or removed.


62-62: Prevent accidental removal of non-related elements.

$(this).find('.wpuf-field-button').remove(); effectively clears the button. Double-check that no other elements share the class .wpuf-field-button inside this container. If so, consider scoping more narrowly.


117-118: Clear and concise action button styles.

Defining action_button_classes with a short string is straightforward. Consider moving to a design utility layer if these classes are reused across multiple components.


121-130: Computed property for dynamic column classes.

This is a good approach for programmatically generating column classes based on the number of columns. Keep an eye on potential off-by-one errors if the number of columns changes outside the expected range.

admin/form-builder/assets/js/components/builder-stage-v4-1/template.php (8)

1-6: Improved blank-state UX.

Displaying a helpful illustration and guidance text when no form fields are present is an excellent user experience enhancement.


8-10: Label type binding is flexible.

Binding :class="['form-label-' + label_type]" seamlessly handles label styling. Ensure label_type is consistently set and validated in your Vuex/store or parent component.


16-21: Conditional classes for form fields.

Applying multiple classes conditionally ('field-items', 'wpuf-el', ...) is helpful for styling and referencing. Confirm consistency with existing field-specific CSS rules.


23-25: Highlighting selected fields.

The class logic applies a distinct border and background color when editing_form_id matches the current field ID. This improves the editing experience. Ensure unused states are gracefully handled (e.g., no editing field).


83-95: Handling invalid fields gracefully.

Disabling controls for fields that failed validation is effective. Confirm that the user receives adequate feedback on why a field is invalid and how to fix it.


126-131: Hidden fields grouping.

Providing a dedicated section for hidden fields, along with clarity on keys and values, is beneficial. Ensure that any toggling logic or advanced settings for hidden fields are documented for future maintainers.


139-193: Consistent control layout.

Reusing the same approach for hover-based control buttons in hidden fields ensures UI uniformity. Verify that the styling and control states match the main field items for a cohesive user experience.


197-198: Customizable bottom area.

do_action( 'wpuf_form_builder_template_builder_stage_bottom_area' ) allows further extensibility. Good practice for plugin-based extension in the WordPress ecosystem.

includes/Admin/Forms/Admin_Form.php (9)

199-199: Conditional rendering for Post Settings.

Using v-show="active_settings_tab === '#wpuf-metabox-settings'" is a straightforward and performant solution for toggling sections. Double-check that the default tab is set properly.


203-203: Consistent tab structure.

Ensuring uniform naming conventions (#wpuf-metabox-settings-update) keeps the code base coherent and predictable, especially where IDs or anchors are used across multiple files.


207-207: Clear naming for submission restrictions.

Making the tab ID #wpuf-metabox-submission-restriction explicit clarifies its functionality. Verify that any references to the older ID are also updated.


211-211: Explicit Payment Settings tab.

This ensures logical separation of payment-related configurations from other settings, making the UI more user-friendly.


215-215: Dedicated Display Settings tab.

Following the same pattern, the display tab provides clarity on customizing how the form is rendered. This fosters better UX for end users.


219-219: Post Expiration handling.

The newly introduced tab #wpuf-metabox-post_expiration calls form_post_expiration(). Ensure any advanced expiration logic is validated in the context of user roles or custom post types.


237-254: Dynamic tab highlighting for Post/Edit/Restrictions/etc.

Binding the nav-tab-active class to the condition :class="active_settings_tab === '...'" is elegant. Ensure the default active tab is set appropriately if a user visits these settings for the first time.


270-274: Additional Notification tab.

Adding a dedicated “Notification” tab for post forms centralizes email or admin notice settings. Double-check that references to the new tab remain consistent with the rest of the builder logic.


290-290: Conditional content blocks in “Notification” tab.

The v-show="active_tab === 'notification'" ensures the content is only displayed when relevant. Test thoroughly to confirm that any asynchronous calls or template logic are properly bound to the tab’s state.

includes/Admin/Posting.php (2)

25-25: Assert code consistency for action hooks.

Adding admin_enqueue_scripts for dequeue_assets is consistent with the approach. However, ensure that dequeue_assets doesn't conflict with other asset-loading sequences in the admin area.


63-69: Confirm style handle availability.

When enqueuing either wpuf-admin-form-builder or wpuf-form-builder, confirm both style handles are actually registered. If one of them is missing, you may end up with an unregistered handle error.

includes/Fields/Field_Contract.php (1)

381-381: Improve clarity in help text.

Changing from “Read only” to “Make this field read only” is clearer. You may want to mention explicitly if it’s only for frontend forms to reduce confusion.

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

610-610: Validate field_options usage.

When mixing field_options with form_field_mixin, ensure you handle potential conflicts in watchers or computed properties between these mixins.


805-806: Good approach for combining mixins.

Combining option_field_mixin and form_field_mixin can reduce duplication. This looks consistent with your approach in other fields.


876-877: Ensure consistent approach for multiline fields.

wpuf_mixins.form_field_mixin usage in field-textarea is consistent with text fields. Verify the watch or computed properties manage multiline input properly.


897-898: Check naming consistency of "visibility" field.

Confirm that the naming (field-visibility) matches any usage in the code or data store. Potential confusion can arise if the naming doesn’t match the data pieces used elsewhere.


Line range hint 1028-1061: Leverage internal sorting or reorder strategy for columns.

The code manipulates column fields’ drag/drop logic. Confirm that you have robust error handling if multiple simultaneous drags occur or if the user moves a field to an invalid column.


1548-1664: Search-based panel filtering is well-integrated.

The approach to filter panel sections based on the user’s search text is clean. Double-check edge cases, such as an empty or special-character search, to avoid partial or unintended matches.

🧰 Tools
🪛 Biome (1.9.4)

[error] 1618-1618: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 1641-1641: This aliasing of this is unnecessary.

Arrow functions inherits this from their enclosing scope.
Safe fix: Use this instead of an alias.

(lint/complexity/noUselessThisAlias)

includes/Admin/Admin_Subscription.php (1)

251-251: LGTM!

Using a fallback 0 if billing_amount is not set avoids undefined index notices. This is a clean fix for potential errors.

admin/form-builder/assets/js/components/form-checkbox_field/template.php (1)

2-17: 🛠️ Refactor suggestion

Add key attribute to v-for directive for optimal rendering performance.

The v-for directive is missing a key attribute, which Vue.js requires for optimal list rendering and maintaining component state.

Apply this diff:

-            v-if="has_options" v-for="(label, val) in field.options"
+            v-if="has_options" v-for="(label, val) in field.options" :key="val"

Please ensure that:

  1. The builder_class_names('checkbox') method is properly implemented
  2. The is_selected method correctly validates the checkbox state
✅ Verification successful

Let me verify the concerns by checking the implementation of the mentioned methods.

This will help us verify:

  1. The implementation of builder_class_names method
  2. The implementation of is_selected method
  3. The location of the component's script file to check the methods' implementations

Let me try a different approach to find these implementations.

This should help us find:

  1. The component's script file with correct extensions
  2. The implementation of both methods either in the component or in a base component/mixin
  3. Any potential base component that might contain these shared methods

Based on the search results, I found that both builder_class_names and is_selected methods are implemented in the form field mixin:

  1. builder_class_names is implemented in admin/form-builder/assets/js/mixins/form-field.js
  2. is_selected is also implemented in the same mixin file with proper array checking logic:
is_selected: function (label) {
    if (_.isArray(this.field.selected)) {
        if (_.indexOf(this.field.selected, label) >= 0) {
            return true;
        }
    }
}

The key attribute can be safely added as both required methods are properly implemented.

🏁 Scripts executed

The following scripts were executed for the analysis:

Error: No shell scripts found


Script:

#!/bin/bash
# Search for builder_class_names implementation
ast-grep --pattern 'builder_class_names'

# Search for is_selected implementation in the component
ast-grep --pattern 'is_selected'

# Find the component's script file
fd "form-checkbox_field" --type f

Length of output: 107


Script:

#!/bin/bash
# Search for the component's script file with a more specific pattern
fd "form-checkbox_field" --type f --extension js --extension vue

# Use ripgrep to search for method implementations
rg "builder_class_names" -A 5
rg "is_selected" -A 5

# Look for any base component or mixin that might contain these methods
rg "export default" -A 10 --type js

Length of output: 35468

Comment on lines +129 to +131
if ( ! $registry ) {
break;
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Provide fallback or explanatory UI when no templates are available

When $registry is empty, the logic breaks out without informing the user. Consider gracefully handling the empty state by providing a helpful message or alternative UI.

 if ( ! $registry ) {
+   echo '<p>' . esc_html__( 'No form templates available.', 'wp-user-frontend' ) . '</p>';
    break;
 }
📝 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
if ( ! $registry ) {
break;
}
if ( ! $registry ) {
echo '<p>' . esc_html__( 'No form templates available.', 'wp-user-frontend' ) . '</p>';
break;
}

Comment on lines +91 to +119
<div class="wpuf-relative wpuf-group">
<?php
if ( $image ) {
printf( '<img src="%s" alt="%s">', esc_attr( $image ), esc_attr( $title ) );
}
?>
<p class="wpuf-font-medium wpuf-text-gray-700 wpuf-flex wpuf-items-center wpuf-justify-center">
<?php
echo esc_html( $title );
if ( file_exists( $crown_icon ) ) {
printf( '<span class="pro-icon-title wpuf-ml-2"> %s</span>', file_get_contents( $crown_icon ) );
}
?>
</p>

<div class="wpuf-absolute wpuf-opacity-0 group-hover:wpuf-opacity-100 wpuf-transition-all wpuf-z-10 wpuf-text-center wpuf-flex wpuf-flex-col wpuf-bg-green-700/70 wpuf-h-full wpuf-w-full wpuf-top-0 wpuf-left-0 wpuf-text-white wpuf-p-10 wpuf-rounded-md wpuf-flex wpuf-items-center wpuf-justify-center">
<a href="<?php echo esc_url( Pro_Prompt::get_upgrade_to_pro_popup_url() ); ?>"
target="_blank"
class="wpuf-btn-primary wpuf-flex wpuf-items-center wpuf-w-max"
title="<?php echo esc_attr( $template->get_title() ); ?>" >
<?php
esc_html_e( 'Upgrade to PRO', 'wp-user-frontend' );
if ( file_exists( $crown_icon ) ) {
printf( '<span class="pro-icon wpuf-ml-2"> %s</span>', file_get_contents( $crown_icon ) );
}
?>
</a>
</div>
</li>
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Mismatched closing tag for <li>
It appears that there is a stray </li> tag at line 119 without a corresponding opening <li> tag. This may cause unexpected layout or styling issues.

Below is a possible fix to replace </li> with </div>:

-                        </li>
+                        </div>
📝 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
<div class="wpuf-relative wpuf-group">
<?php
if ( $image ) {
printf( '<img src="%s" alt="%s">', esc_attr( $image ), esc_attr( $title ) );
}
?>
<p class="wpuf-font-medium wpuf-text-gray-700 wpuf-flex wpuf-items-center wpuf-justify-center">
<?php
echo esc_html( $title );
if ( file_exists( $crown_icon ) ) {
printf( '<span class="pro-icon-title wpuf-ml-2"> %s</span>', file_get_contents( $crown_icon ) );
}
?>
</p>
<div class="wpuf-absolute wpuf-opacity-0 group-hover:wpuf-opacity-100 wpuf-transition-all wpuf-z-10 wpuf-text-center wpuf-flex wpuf-flex-col wpuf-bg-green-700/70 wpuf-h-full wpuf-w-full wpuf-top-0 wpuf-left-0 wpuf-text-white wpuf-p-10 wpuf-rounded-md wpuf-flex wpuf-items-center wpuf-justify-center">
<a href="<?php echo esc_url( Pro_Prompt::get_upgrade_to_pro_popup_url() ); ?>"
target="_blank"
class="wpuf-btn-primary wpuf-flex wpuf-items-center wpuf-w-max"
title="<?php echo esc_attr( $template->get_title() ); ?>" >
<?php
esc_html_e( 'Upgrade to PRO', 'wp-user-frontend' );
if ( file_exists( $crown_icon ) ) {
printf( '<span class="pro-icon wpuf-ml-2"> %s</span>', file_get_contents( $crown_icon ) );
}
?>
</a>
</div>
</li>
<div class="wpuf-relative wpuf-group">
<?php
if ( $image ) {
printf( '<img src="%s" alt="%s">', esc_attr( $image ), esc_attr( $title ) );
}
?>
<p class="wpuf-font-medium wpuf-text-gray-700 wpuf-flex wpuf-items-center wpuf-justify-center">
<?php
echo esc_html( $title );
if ( file_exists( $crown_icon ) ) {
printf( '<span class="pro-icon-title wpuf-ml-2"> %s</span>', file_get_contents( $crown_icon ) );
}
?>
</p>
<div class="wpuf-absolute wpuf-opacity-0 group-hover:wpuf-opacity-100 wpuf-transition-all wpuf-z-10 wpuf-text-center wpuf-flex wpuf-flex-col wpuf-bg-green-700/70 wpuf-h-full wpuf-w-full wpuf-top-0 wpuf-left-0 wpuf-text-white wpuf-p-10 wpuf-rounded-md wpuf-flex wpuf-items-center wpuf-justify-center">
<a href="<?php echo esc_url( Pro_Prompt::get_upgrade_to_pro_popup_url() ); ?>"
target="_blank"
class="wpuf-btn-primary wpuf-flex wpuf-items-center wpuf-w-max"
title="<?php echo esc_attr( $template->get_title() ); ?>" >
<?php
esc_html_e( 'Upgrade to PRO', 'wp-user-frontend' );
if ( file_exists( $crown_icon ) ) {
printf( '<span class="pro-icon wpuf-ml-2"> %s</span>', file_get_contents( $crown_icon ) );
}
?>
</a>
</div>
</div>

>
<span v-if="field.help" class="wpuf-help" v-html="field.help" />
<p v-if="field.help" class="wpuf-mt-2 wpuf-text-sm wpuf-text-gray-500" v-html="field.help"></p>
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Check for potential XSS through “v-html” usage.
v-html="field.help" will render raw HTML and can expose the app to XSS if field.help is not sanitized. Confirm that the field's content is trusted or sanitized server-side.

:placeholder="field.placeholder"
:value="field.default"
:size="field.size"
>

<span v-if="field.help" class="wpuf-help" v-html="field.help" />
<p v-if="field.help" class="wpuf-mt-2 wpuf-text-sm wpuf-text-gray-500" v-html="field.help"></p>
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Potential XSS through “v-html”.
Same concern as in other files—ensure field.help is sanitized to mitigate XSS risks.

:rows="field.rows"
:cols="field.cols"
>{{ field.default }}</textarea>

<text-editor v-if="'no' !== field.rich" :rich="field.rich" :default_text="field.default"></text-editor>

<span v-if="field.help" class="wpuf-help" v-html="field.help" ></span>
<p v-if="field.help" class="wpuf-mt-2 wpuf-text-sm wpuf-text-gray-500" v-html="field.help"></p>
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Prevent XSS on help text.
v-html="field.help" can render malicious HTML if field.help is not sanitized. Confirm the data is validated prior to binding.

:placeholder="field.placeholder"
:default_text="field.default"
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Review duplication of default text.
You have :default_text="field.default" and also {{ field.default }} within <textarea>. This can cause confusion or duplication in your final output. Consider removing one to keep the logic consistent.

<textarea
    v-if="'no' === field.rich"
    :class="builder_class_names('textareafield')"
    :placeholder="field.placeholder"
-    :default_text="field.default"
    :rows="field.rows"
    :cols="field.cols"
>{{ field.default }}</textarea>

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

Comment on lines +6 to +10
<div class="option-fields-section wpuf-relative">
<p
@click="showOptions = !showOptions"
class="wpuf-flex wpuf-items-center wpuf-justify-between wpuf-min-w-full wpuf-rounded-md wpuf-py-1 wpuf-px-2 wpuf-text-gray-900 !wpuf-shadow-sm placeholder:wpuf-text-gray-400 sm:wpuf-text-sm sm:wpuf-leading-6 wpuf-border !wpuf-border-gray-300 wpuf-max-w-full hover:wpuf-cursor-pointer"
>
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Replace paragraph with a button or ARIA attributes for improved accessibility.
While a clickable <p> can be styled to resemble a button, consider using a <button> or implementing ARIA attributes for accessibility compliance.

-<p
-    @click="showOptions = !showOptions"
-    class="..."
->
+</p>
+<button
+    type="button"
+    @click="showOptions = !showOptions"
+    class="..."
+    aria-haspopup="listbox"
+>

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

Comment on lines +40 to +50
$post_form_page = 'wpuf-post-forms';

if ( strpos( get_current_screen()->id, $post_form_page ) === false ) {
return;
}

wp_dequeue_style( 'wpuf-form-builder' );
if ( defined( 'WPUF_PRO_VERSION' ) && version_compare( WPUF_PRO_VERSION, '4.1', '<' ) ) {
wp_dequeue_style( 'wpuf-form-builder-pro' );
}
}
Copy link

Choose a reason for hiding this comment

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

💡 Codebase verification

The current screen ID check should be exact to prevent unintended matches.

Based on the codebase analysis, the screen ID wpuf-post-forms is used consistently throughout the codebase as an exact identifier for the post forms page. The current strpos check could indeed lead to false positives with URLs like wpuf-post-forms-duplicate or similar variations. This is particularly important because:

  1. The screen ID is used in menu registration: add_submenu_page(..., 'wpuf-post-forms', ...)
  2. The ID is used for exact matching in other parts of the code: return 'wpuf-post-forms' === $page ? true : false;
  3. All URL constructions in the codebase use the exact wpuf-post-forms value

The suggested refactor to use an exact match is correct:

- if ( strpos( get_current_screen()->id, $post_form_page ) === false ) {
+ if ( $post_form_page !== get_current_screen()->id ) {
🔗 Analysis chain

Validate the screen ID match.

The code checks for strpos( get_current_screen()->id, $post_form_page ) === false. In some edge cases, partial matches (e.g., wpuf-post-forms-duplicate) could mistakenly pass or fail. If you want an exact match, verify you do not inadvertently match sub-strings.

- if ( strpos( get_current_screen()->id, $post_form_page ) === false ) {
+ if ( $post_form_page !== get_current_screen()->id ) {

Let me gather more information about the screen ID usage in the codebase.

🏁 Scripts executed

The following scripts were executed for the analysis:

Error: No shell scripts found


Script:

#!/bin/bash
# Search for other occurrences of screen ID comparisons
rg "get_current_screen\(\)->id" -B 2 -A 2

# Search for definitions or usage of wpuf-post-forms
rg "wpuf-post-forms" -B 2 -A 2

# Look for any menu/page registration that might define these screen IDs
ast-grep --pattern 'add_menu_page($$$)' 
ast-grep --pattern 'add_submenu_page($$$)'

Length of output: 17120

Comment on lines +19 to +34
<div
v-else
class="wpuf-flex"
>
<div
v-if="has_options" v-for="(label, val) in field.options"
class="wpuf-relative wpuf-flex wpuf-items-center wpuf-mr-4">
<input
type="checkbox"
:value="val"
:checked="is_selected(val)"
:class="class_names('checkbox_btns')"
class="!wpuf-mt-[.5px] wpuf-rounded wpuf-border-gray-300 wpuf-text-indigo-600">
<label class="wpuf-ml-1 wpuf-text-sm wpuf-font-medium wpuf-text-gray-900">{{ label }}</label>
</div>
</div>
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Improve inline checkbox implementation for better maintainability.

Several issues need attention:

  1. Inconsistent method naming between class_names and builder_class_names
  2. Use of hardcoded !important modifier
  3. Missing key attribute in v-for directive

Apply these changes:

-            v-if="has_options" v-for="(label, val) in field.options"
+            v-if="has_options" v-for="(label, val) in field.options" :key="val"
-                :class="class_names('checkbox_btns')"
-                class="!wpuf-mt-[.5px] wpuf-rounded wpuf-border-gray-300 wpuf-text-indigo-600">
+                :class="[
+                    builder_class_names('checkbox_btns'),
+                    'wpuf-mt-0.5 wpuf-rounded wpuf-border-gray-300 wpuf-text-indigo-600'
+                ]">
📝 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
<div
v-else
class="wpuf-flex"
>
<div
v-if="has_options" v-for="(label, val) in field.options"
class="wpuf-relative wpuf-flex wpuf-items-center wpuf-mr-4">
<input
type="checkbox"
:value="val"
:checked="is_selected(val)"
:class="class_names('checkbox_btns')"
class="!wpuf-mt-[.5px] wpuf-rounded wpuf-border-gray-300 wpuf-text-indigo-600">
<label class="wpuf-ml-1 wpuf-text-sm wpuf-font-medium wpuf-text-gray-900">{{ label }}</label>
</div>
</div>
<div
v-else
class="wpuf-flex"
>
<div
v-if="has_options" v-for="(label, val) in field.options" :key="val"
class="wpuf-relative wpuf-flex wpuf-items-center wpuf-mr-4">
<input
type="checkbox"
:value="val"
:checked="is_selected(val)"
:class="[
builder_class_names('checkbox_btns'),
'wpuf-mt-0.5 wpuf-rounded wpuf-border-gray-300 wpuf-text-indigo-600'
]">
<label class="wpuf-ml-1 wpuf-text-sm wpuf-font-medium wpuf-text-gray-900">{{ label }}</label>
</div>
</div>

</div>
</div>

<p v-if="field.help" class="wpuf-mt-2 wpuf-text-sm wpuf-text-gray-500" v-html="field.help"></p>
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Potential XSS vulnerability in help text rendering.

Using v-html with potentially unsanitized content could expose the application to XSS attacks. Ensure that field.help content is properly sanitized before rendering.

Consider one of these approaches:

  1. Sanitize the help text before assigning to field.help
  2. Use a dedicated HTML sanitizer library
  3. If HTML is not required, use standard text interpolation instead:
- <p v-if="field.help" class="wpuf-mt-2 wpuf-text-sm wpuf-text-gray-500" v-html="field.help"></p>
+ <p v-if="field.help" class="wpuf-mt-2 wpuf-text-sm wpuf-text-gray-500">{{ field.help }}</p>

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

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

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

122-122: Spacing cleanup
Removing redundant spaces in connectToSortable enhances readability. Functionality remains intact.

admin/form-builder/assets/js/components/form-fields-v4-1/index.js (1)

99-101: Resetting panel sections
set_default_panel_sections reverts to default. Makes it easier to refresh the UI if the user tries different filters or manipulations.

Consider clarifying in code comments that this method reverts the user’s panel filters/sections to the plugin’s default structure.

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

957-961: Commented-out code
Leaving a clear comment for future reference or debugging might be beneficial if these lines are planned for re-introduction. Otherwise, consider removing if no longer needed.

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

957-961: Commented-out resizing
If no longer needed, removing it would further reduce code clutter. Otherwise, leaving a clarifying comment is advisable.

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

1652-1692: Optimize search performance with debouncing

The search functionality directly filters on every input change. Consider implementing debouncing to reduce unnecessary re-renders and improve performance, especially with a large number of fields.

+ data: function () {
+    return {
+        searchTimeout: null,
+        ...this.$data
+    }
+ },
  watch: {
      searched_fields: function ( searchValue ) {
+         if (this.searchTimeout) {
+             clearTimeout(this.searchTimeout);
+         }
+         this.searchTimeout = setTimeout(() => {
              // Existing search logic
+         }, 300);
      }
  }

331-333: Refactor code based on static analysis suggestions

Several code quality improvements can be made:

  1. Simplify boolean expressions
  2. Use optional chaining
  3. Remove unnecessary this aliasing
- return (this.field_settings[template] && this.field_settings[template].pro_feature) ? true : false;
+ return Boolean(this.field_settings[template]?.pro_feature);

- if (this.field_settings[template] && this.field_settings[template].is_full_width) {
+ if (this.field_settings[template]?.is_full_width) {

- var self = this;
- self.options.splice(index, 1);
+ this.options.splice(index, 1);

Also applies to: 354-356, 362-364

🧰 Tools
🪛 Biome (1.9.4)

[error] 332-332: Unnecessary use of boolean literals in conditional expression.

Simplify your code by directly assigning the result without using a ternary operator.
If your goal is negation, you may use the logical NOT (!) or double NOT (!!) operator for clearer and concise code.
Check for more details about NOT operator.
Unsafe fix: Remove the conditional expression with

(lint/complexity/noUselessTernary)


[error] 332-332: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

assets/js-templates/form-components.php (1)

1047-1060: Enhance search field accessibility

The search implementation could benefit from additional accessibility attributes:

 <input
     type="text"
     name="search"
     id="search"
     v-model="searched_fields"
+    role="searchbox"
+    aria-label="Search fields"
+    aria-describedby="search-description"
     class="!wpuf-border-none !wpuf-rounded-lg wpuf-block wpuf-min-w-0 wpuf-grow wpuf-px-4 wpuf-py-1.5 wpuf-text-base wpuf-text-gray-900 placeholder:wpuf-text-gray-400 sm:wpuf-text-sm/6 !wpuf-shadow-none !wpuf-ring-transparent"
     placeholder="<?php esc_attr_e( 'Search Field', 'wp-user-frontend' ); ?>">
+<span id="search-description" class="wpuf-sr-only">
+    <?php esc_html_e( 'Type to search available form fields', 'wp-user-frontend' ); ?>
+</span>
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b06bc5c and 5139424.

📒 Files selected for processing (10)
  • admin/form-builder/assets/js/components/form-fields-v4-1/index.js (1 hunks)
  • admin/form-builder/assets/js/components/form-fields-v4-1/template.php (1 hunks)
  • admin/form-builder/assets/js/form-builder.js (13 hunks)
  • admin/form-builder/views/form-builder-v4.1.php (1 hunks)
  • assets/css/frontend-forms.css (2 hunks)
  • assets/js-templates/form-components.php (16 hunks)
  • assets/js/wpuf-form-builder-components.js (12 hunks)
  • assets/js/wpuf-form-builder-wpuf-forms.js (2 hunks)
  • assets/js/wpuf-form-builder.js (13 hunks)
  • assets/less/frontend-forms.less (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • admin/form-builder/views/form-builder-v4.1.php
  • admin/form-builder/assets/js/components/form-fields-v4-1/template.php
  • assets/css/frontend-forms.css
🧰 Additional context used
🪛 Biome (1.9.4)
assets/js/wpuf-form-builder-components.js

[error] 332-332: Unnecessary use of boolean literals in conditional expression.

Simplify your code by directly assigning the result without using a ternary operator.
If your goal is negation, you may use the logical NOT (!) or double NOT (!!) operator for clearer and concise code.
Check for more details about NOT operator.
Unsafe fix: Remove the conditional expression with

(lint/complexity/noUselessTernary)


[error] 332-332: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 355-355: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 363-363: Unnecessary use of boolean literals in conditional expression.

Simplify your code by directly assigning the result without using a ternary operator.
If your goal is negation, you may use the logical NOT (!) or double NOT (!!) operator for clearer and concise code.
Check for more details about NOT operator.
Unsafe fix: Remove the conditional expression with

(lint/complexity/noUselessTernary)


[error] 301-301: This aliasing of this is unnecessary.

Arrow functions inherits this from their enclosing scope.
Safe fix: Use this instead of an alias.

(lint/complexity/noUselessThisAlias)


[error] 1630-1630: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

admin/form-builder/assets/js/components/form-fields-v4-1/index.js

[error] 83-83: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

🔇 Additional comments (71)
assets/less/frontend-forms.less (2)

259-259: LGTM: Editor wrap border removal.

The removal of the border from .wp-editor-wrap creates a cleaner, more modern look for the editor interface.


2070-2074: LGTM: Form preview dropzone styling.

The dropzone styling uses semantic colors (green background and border) to provide clear visual feedback for drag and drop interactions.

A few observations about the implementation:

  • The light green background (#f0fdf4) provides good contrast for content
  • The green border (#4ade80) clearly indicates the drop target area
  • The fixed height ensures consistent spacing in the layout
assets/js/wpuf-form-builder-wpuf-forms.js (2)

111-111: Typographical fix is properly applied
The correction from "destroy" ensures clarity in the code comments. No further changes needed.


113-113: Selector refinement
Changing from a broad '.button' class to '.wpuf-field-button' helps precisely target the intended elements. Good improvement for clarity and maintainability.

admin/form-builder/assets/js/components/form-fields-v4-1/index.js (7)

1-14: New component introduction
This new form-fields-v4-1 component structure is clear and follows Vue best practices. Good job organizing the data properties (searched_fields, asset_url) for easy reference.


30-49: Draggable initialization
The approach of cleaning up previous jQuery UI draggable instances and re-initializing them is sound. Ensures the elements do not stack multiple draggable bindings.


52-55: Toggle panel sections
panel_toggle commits a Vuex mutation to handle panel visibility. Straightforward and maintainable approach for toggling UI states.


57-59: Pro feature verification
Neat function to determine if a field is a pro feature. This improves clarity for end-users on restricted functionalities.


61-78: Upsell workflow
alert_pro_feature uses SweetAlert. The styling and logic look correct. Good reusability for product upsells.


80-92: Validation workflow
alert_invalidate_msg gracefully warns about invalid or incomplete fields. The approach is well-structured and user-friendly.

🧰 Tools
🪛 Biome (1.9.4)

[error] 83-83: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


104-145: Responsive search & re-render
The watcher on searched_fields resets panel sections, re-initializes draggable, and filters the fields dynamically. This thoroughly addresses the real-time search use case.

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

44-47: Conditional logic for older form panels
You’re correctly deciding which panel (older vs. new) to present based on is_older_form and post.post_type. Great approach to unify new and legacy form builder experiences.


73-73: Reset field editing
Resetting editing_field_id to 0 is a good practice when switching to the “form-fields” or “form-fields-v4-1” panel, preventing stale references.


93-96: Filtering for field settings
Lines 94-96 retrieve the relevant field from form_fields. The code is concise.


106-108: Async delayed setting
Using setTimeout to set editing_field_id ensures the panel properly re-renders, preventing potential race conditions in Vue.


245-245: Panel update after deletion
Shifting state.current_panel to form-fields-v4-1 if it’s not an older form keeps the UI consistent with the newly introduced interface.


392-392: Consistent panel selection for column field removal
Same logic for column fields: ensures the UI does not get stuck in the wrong panel.


396-404: Panel section management
set_panel_sections and set_default_panel_sections provide seamless reconfigurations or resets of the form builder’s panel structure. This is flexible and easy to maintain.


423-428: User interface states
Adding reactive data like enableMultistep, shortcodeCopied, active_tab, and active_settings_tab significantly expands the plugin’s user experience potential.


466-466: Meta field key generation
Concise mapping for generating placeholders from the field name. The approach is straightforward.


489-491: Clipboard initialization
Binding a new Clipboard instance to .form-id is a neat approach for easily copying shortcodes.


493-493: Tooltip activation
Calling $(".form-id").tooltip(); ensures immediate help text for the user. Good call for usability.


495-500: Conditional for post forms
Attaching click listeners only if this.is_post_form is a practical approach, avoiding extraneous event binding on other form types.


501-517: Copy success logic
This block updates tooltip text on copy and reverts it after a short interval. Great user feedback.


518-518: Empty block
No functional difference introduced here. Good to see code cleanliness.


519-524: Unload warning
Prompting the user upon unsaved changes is a great safeguard.


525-526: Alternate nav tab binding
For non-post forms, separate tab logic is consistent with the overall approach.


528-529: Secondary settings tab handling
These lines gather references to .tab-contents .group for more targeted manipulations. Neat separation for bigger UIs.


531-532: Default active tab
Selecting the first tab and showing the first group streamlines the initial user experience.


534-534: Tab click binding
Reusing bind_tab_on_click method keeps the code DRY.


536-536: Reinitializing clipboard
Same logic for older forms. Ensures a consistent user experience.


537-540: Tooltip text refactor
Appropriately sets the “Shortcode copied!” message. Clear user feedback.


542-542: State toggling
shortcodeCopied set to true at line 542. Straightforward.


544-549: Tooltip revert timer
Setting a 1-second timeout is a standard approach, ensuring the success message remains visible briefly.


551-552: Clipboard clearing
Finalizing the copy action so the user can repeat without leftover states.


553-553: No further changes here


554-559: Protect unsaved changes
As with older forms, window.onbeforeunload warns of unsaved data. Good parity across code paths.


579-581: Active settings tab
setActiveSettingsTab quickly updates active_settings_tab. Satisfies the user’s expectation of immediate reactivity.


597-598: Panel fallback before save
Switching to either 'form-fields' or 'form-fields-v4-1' prior to saving the form is consistent with the rest of the flow.


609-609: Immediate panel set
self.set_current_panel(panel) ensures the correct panel is displayed post-save, clarifying the user’s next step.

assets/js/wpuf-form-builder.js (29)

44-47: Adaptive panel handling
Same approach for older vs. new forms. This straightforward logic helps unify form builder usage.


73-73: Reset field editing
As above, resetting editing_field_id avoids references to a removed or changed field.


93-96: Targeted field lookups
Retrieves the appropriate field for editing. The usage of filter is concise.


106-108: Async reactivity
The setTimeout fix is repeated here for ensuring a clean re-render.


245-245: Consistent panel post-deletion
Reverts to 'form-fields-v4-1' if it’s a newer form. Maintains a smooth user experience.


392-392: Column field panel fix
Same approach ensures column field removal also respects the new panel logic.


396-404: Panel sections
set_panel_sections and set_default_panel_sections mirror the logic used in the related script, ensuring consistent code in multiple areas.


423-428: Extended data properties
The new data properties (shortcodeCopied, etc.) reflect the plugin’s broader UI enhancements.


466-466: Meta field placeholders
Generates a string of placeholders for meta fields. Light and efficient solution for shortcodes or templates.


489-491: Clipboard constructor
Identical usage to the other file. Good for cross-consistency in the codebase.


493-493: Tooltip
Same approach to activate the tooltip. Straightforward user experience improvement.


495-500: Event binding for post form
Consistent check for is_post_form ensures no overhead for pages that do not need it.


501-517: Copy success feedback
Mirrors the logic of the other file. Great consistency across the builder.


518-518: No functional change


519-524: Unload safety
User is warned when leaving the page with unsaved changes, preventing data loss.


525-526: Tab logic for advanced forms
Keeps the tab interactions coherent for non-post forms.


528-529: Additional references
Grabbing .tab-contents .group ensures dynamic updates.


531-532: Defaulting to first tab
Helps new or returning users know where to start.


534-534: Method reuse
bind_tab_on_click is invoked again, continuing the DRY principle.


536-536: Clipboard logic repeated
Idempotent code ensuring uniform copying functionality.


537-540: Friendly message
Reminding users the copy was successful.


542-542: Shortcode state
Toggling shortcodeCopied is instant feedback.


544-549: Timeout revert
Same approach ensures the message does not linger too long.


551-552: Cleanup
Ensures subsequent copy actions remain accurate.


553-553: No changes


554-559: Window unload
Repeats the unsaved-changes confirmation. Good for user safety.


579-581: Tab switching
setActiveSettingsTab is a compact function. Perfectly suits the needed use case.


597-598: Fallback to correct panel
Reaffirming the panel switch logic during form saving.


609-609: Panel reset after save
Calling set_current_panel is consistent with changes above.

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

258-260: Verify the selector change impact on draggable functionality

The selector for removing buttons from the stage has been changed from .button.ui-draggable.ui-draggable-handle to .wpuf-field-button. While this aligns with the new styling approach, we should ensure this change doesn't break the draggable functionality in older templates.

✅ Verification successful

The selector change is properly synchronized with draggable functionality

The code analysis shows that the selector change from .button.ui-draggable.ui-draggable-handle to .wpuf-field-button is properly synchronized across the codebase:

  1. The new .wpuf-field-button class is consistently used in the draggable initialization code:
var buttons = $(self.$el).find('.panel-form-field-buttons .wpuf-field-button');
buttons.draggable({
    connectToSortable: '#form-preview-stage .wpuf-form, .wpuf-column-inner-fields .wpuf-column-fields-sortable-list',
    helper: 'clone',
    revert: 'invalid'
});
  1. The class is properly defined in the templates:
class="wpuf-field-button wpuf-relative wpuf-flex wpuf-items-center wpuf-rounded-lg wpuf-border wpuf-border-gray-200 wpuf-bg-white wpuf-shadow-sm wpuf-p-3 hover:wpuf-border-gray-300 hover:wpuf-cursor-pointer"
  1. The draggable functionality is properly maintained with proper cleanup and reinitialization:
if ($(this).draggable('instance')) {
    $(this).draggable('destroy');
}
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if the old selector is still in use anywhere in the codebase
rg -l "button.ui-draggable.ui-draggable-handle"

# Check for any potential draggable initialization with the new selector
rg -l "wpuf-field-button.*draggable"

Length of output: 233


Script:

#!/bin/bash
# Let's examine the actual implementation and usage context
rg "button.ui-draggable.ui-draggable-handle" -A 3 -B 3

# Check for any draggable initialization patterns
rg "wpuf-field-button" -A 3 -B 3

# Look for jQuery draggable initialization
rg "draggable\(" -A 3 -B 3

Length of output: 26758

assets/js-templates/form-components.php (1)

87-91: Well-implemented empty state UI pattern

The empty state implementation follows good UX practices by:

  • Providing clear visual feedback with an illustration
  • Including descriptive text to guide users
  • Maintaining visual hierarchy with appropriate typography

Comment on lines +777 to +782
data: function () {
return {
showOptions: false,
selectedOption: 'Select an option',
};
},
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Enhance accessibility for custom dropdown implementation

The custom dropdown implementation should include ARIA attributes and keyboard navigation support for better accessibility. Consider adding:

  • aria-expanded for dropdown state
  • role="listbox" and role="option" for semantic meaning
  • Keyboard event handlers for arrow keys, Enter, and Escape
 data: function () {
     return {
         showOptions: false,
         selectedOption: 'Select an option',
+        // Add aria attributes
+        ariaExpanded: false,
+        activeDescendant: null
     };
 },

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

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (8)
src/css/admin/form-builder.css (1)

58-63: Avoid overriding the background-color with background
You have declared background-color: #ffffff; on line 60 and then overridden it with background: repeating-linear-gradient(...) on line 62. If you intend to combine both, please consider leveraging layered background properties (e.g., background-image) to avoid potential conflicts.

-    background-color: #ffffff;
-    background: repeating-linear-gradient( -45deg, #dcfce7, #dcfce7 2px, #ffffff 2px, #ffffff 6px );
+    background-color: #ffffff;
+    background-image: repeating-linear-gradient(
+      -45deg,
+      #dcfce7,
+      #dcfce7 2px,
+      #ffffff 2px,
+      #ffffff 6px
+    );
🧰 Tools
🪛 Biome (1.9.4)

[error] 62-62: Unexpected shorthand property background after background-color

(lint/suspicious/noShorthandPropertyOverrides)

admin/form-builder/assets/js/components/form-fields-v4-1/index.js (1)

80-93: Use optional chaining to simplify the validator check
To cleanly check for validator and validator.msg, consider using optional chaining for improved readability.

- if (validator && validator.msg) {
+ if (validator?.msg) {
🧰 Tools
🪛 Biome (1.9.4)

[error] 83-83: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

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

355-358: Replace ternary with direct boolean usage
Static analysis suggests removing unneeded boolean literals in conditional expressions, such as:

return this.field_settings[template] && this.field_settings[template].is_full_width ? true : false;

You may simplify to:

return !!(this.field_settings[template]?.is_full_width);
🧰 Tools
🪛 Biome (1.9.4)

[error] 355-355: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


363-364: Simplify conditional usage
Likewise, you can remove unnecessary boolean literals:

- return ( field.recaptcha_type && 'invisible_recaptcha' === field.recaptcha_type ) ? true : false;
+ return field.recaptcha_type && field.recaptcha_type === 'invisible_recaptcha';
🧰 Tools
🪛 Biome (1.9.4)

[error] 363-363: Unnecessary use of boolean literals in conditional expression.

Simplify your code by directly assigning the result without using a ternary operator.
If your goal is negation, you may use the logical NOT (!) or double NOT (!!) operator for clearer and concise code.
Check for more details about NOT operator.
Unsafe fix: Remove the conditional expression with

(lint/complexity/noUselessTernary)

assets/js-templates/form-components.php (4)

89-90: Fix duplicate message in blank state.

The same message appears in both the heading and paragraph:

<h2>...<?php esc_html_e( 'Add fields and build your desired form', 'wp-user-frontend' ); ?></h2>
<p>...<?php esc_html_e( 'Add fields and build your desired form', 'wp-user-frontend' ); ?></p>

Consider using different, complementary messages to better guide the user.


743-778: Enhance accessibility of checkbox fields.

While the styling has been improved, consider these accessibility enhancements:

  1. Add aria-label or aria-labelledby to improve screen reader support
  2. Consider adding aria-describedby to link help text with inputs

Example implementation:

 <div class="wpuf-relative wpuf-flex wpuf-items-center">
     <input
         type="checkbox"
         :value="val"
         :checked="is_selected(val)"
+        :aria-label="label"
+        :aria-describedby="'help-' + field.id"
         :class="builder_class_names('checkbox')">
     <label class="wpuf-ml-3 wpuf-text-sm wpuf-font-medium wpuf-text-gray-900">{{ label }}</label>
 </div>
-<p v-if="field.help" class="wpuf-mt-2 wpuf-text-sm wpuf-text-gray-500" v-html="field.help"></p>
+<p v-if="field.help" :id="'help-' + field.id" class="wpuf-mt-2 wpuf-text-sm wpuf-text-gray-500" v-html="field.help"></p>

1051-1057: Enhance search field functionality.

Consider these improvements to the search functionality:

  1. Add aria-label for accessibility
  2. Add debounce to prevent excessive filtering
  3. Add loading state during filtering

Example implementation:

 <input
     type="text"
     name="search"
     id="search"
     v-model="searched_fields"
+    aria-label="<?php esc_attr_e( 'Search form fields', 'wp-user-frontend' ); ?>"
+    @input="debounceSearch"
     class="!wpuf-border-none !wpuf-rounded-lg wpuf-block wpuf-min-w-0 wpuf-grow wpuf-px-4 wpuf-py-1.5 wpuf-text-base wpuf-text-gray-900 placeholder:wpuf-text-gray-400 sm:wpuf-text-sm/6 !wpuf-shadow-none !wpuf-ring-transparent"
     placeholder="<?php esc_attr_e( 'Search Field', 'wp-user-frontend' ); ?>">

1047-1175: Add JSDoc comments to Vue.js templates.

Consider adding JSDoc comments to document the purpose, props, and events of each template. This will improve maintainability and help other developers understand the components better.

Example:

/**
 * Form Fields Panel Component (v4.1)
 * 
 * @template tmpl-wpuf-form-fields-v4-1
 * @description Displays a searchable panel of form fields that can be dragged into the form builder.
 * 
 * @property {Object[]} panel_sections - Sections of form fields
 * @property {Object} field_settings - Settings for each field type
 * @property {string} asset_url - Base URL for assets
 * 
 * @fires add_form_field - When a field is added to the form
 * @fires alert_pro_feature - When a pro feature is clicked
 */
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5139424 and 579dba6.

📒 Files selected for processing (7)
  • admin/form-builder/assets/js/components/form-fields-v4-1/index.js (1 hunks)
  • admin/form-builder/assets/js/components/form-fields-v4-1/template.php (1 hunks)
  • admin/form-builder/assets/js/components/form-fields/index.js (1 hunks)
  • assets/js-templates/form-components.php (16 hunks)
  • assets/js/wpuf-form-builder-components.js (13 hunks)
  • assets/js/wpuf-form-builder-wpuf-forms.js (2 hunks)
  • src/css/admin/form-builder.css (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • assets/js/wpuf-form-builder-wpuf-forms.js
  • admin/form-builder/assets/js/components/form-fields-v4-1/template.php
🧰 Additional context used
🪛 Biome (1.9.4)
src/css/admin/form-builder.css

[error] 81-81: expected } but instead the file ends

the file ends here

(parse)


[error] 62-62: Unexpected shorthand property background after background-color

(lint/suspicious/noShorthandPropertyOverrides)

assets/js/wpuf-form-builder-components.js

[error] 332-332: Unnecessary use of boolean literals in conditional expression.

Simplify your code by directly assigning the result without using a ternary operator.
If your goal is negation, you may use the logical NOT (!) or double NOT (!!) operator for clearer and concise code.
Check for more details about NOT operator.
Unsafe fix: Remove the conditional expression with

(lint/complexity/noUselessTernary)


[error] 332-332: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 355-355: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 363-363: Unnecessary use of boolean literals in conditional expression.

Simplify your code by directly assigning the result without using a ternary operator.
If your goal is negation, you may use the logical NOT (!) or double NOT (!!) operator for clearer and concise code.
Check for more details about NOT operator.
Unsafe fix: Remove the conditional expression with

(lint/complexity/noUselessTernary)


[error] 301-301: This aliasing of this is unnecessary.

Arrow functions inherits this from their enclosing scope.
Safe fix: Use this instead of an alias.

(lint/complexity/noUselessThisAlias)


[error] 1630-1630: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

admin/form-builder/assets/js/components/form-fields-v4-1/index.js

[error] 83-83: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

🔇 Additional comments (11)
admin/form-builder/assets/js/components/form-fields/index.js (1)

26-26: Include #form-preview-stage in draggable connection

This addition looks good and will allow draggable elements to be placed directly onto the #form-preview-stage.

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

188-270: Consistent naming of new component builder-stage-v4-1
The new builder-stage-v4-1 component replicates much of the logic from builder-stage. Ensure all references to versioning or naming are consistent throughout the codebase to avoid confusion.


777-782: [Duplicate Comment] Accessibility improvement needed for custom dropdown
This strongly resembles a comment from a prior review that recommended adding ARIA attributes and keyboard navigation.


805-806: Well-structured mixing approach
Using both wpuf_mixins.option_field_mixin and wpuf_mixins.form_field_mixin together in the field-text component is a good modular approach.


876-877: Keep consistency in mixins usage
Similar to field-text, applying wpuf_mixins.option_field_mixin and wpuf_mixins.form_field_mixin to field-textarea helps maintain consistency.


897-898: Consistent multi-mixin usage
Applying both mixins to field-visibility aligns it with other fields, ensuring consistent data handling and reusability.


Line range hint 1028-1061: Check for double-drag triggers in the column field
While the code sets sortableTriggered flags to avoid double drag triggers, ensure that edge cases with nested or quick drags do not still cause duplicates. Consider adding unit or integration tests covering drag-and-drop scenarios with multiple columns.


1115-1129: Leverage dynamic classes
The computed properties action_button_classes and columnClasses are straightforward, but ensure that the generated classes are consistently applied throughout the UI for a uniform look and feel.


1492-1492: Great extension of connectToSortable
Updating the draggable selector to include #form-preview-stage helps ensure form fields can be placed at the top level as well as in nested columns.


1548-1695: form-fields-v4-1 panel addition
Introducing the new panel for a refined form-builder experience is well-organized. Good job ensuring partial code reuse from the existing form-fields component while introducing the search functionality.

🧰 Tools
🪛 Biome (1.9.4)

[error] 1630-1630: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

assets/js-templates/form-components.php (1)

Line range hint 85-1481: Overall implementation looks great!

The changes successfully modernize the form builder interface with:

  • Clean, modern UI using Tailwind CSS
  • Improved user experience with better visual feedback
  • Consistent styling across components
  • Enhanced drag and drop functionality

The code is well-structured and maintainable. The suggested improvements are minor and can be addressed in follow-up updates.

#wpuf-form-builder .wpuf-fields {
float: none;
width: auto;
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Close the file with a matching brace
Static analysis tools indicate that the file might be missing a closing brace. Double-check that all layers (@layer ... { ... }) and any additional style blocks are syntactically closed.

...
81 }
+}

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

🧰 Tools
🪛 Biome (1.9.4)

[error] 81-81: expected } but instead the file ends

the file ends here

(parse)

Comment on lines +300 to +302
delete_field: function(index) {
var self = this;

Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Remove unnecessary aliasing of this
Using var self = this; in the delete_field: function(index) method is typically unnecessary if you adopt an arrow function in the promise callback (as arrow functions preserve the lexical this).

 delete_field: function(index) {
-    var self = this;

     (Swal.fire({
         text: this.i18n.delete_field_warn_msg,
         ...
📝 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
delete_field: function(index) {
var self = this;
delete_field: function(index) {
🧰 Tools
🪛 Biome (1.9.4)

[error] 301-301: This aliasing of this is unnecessary.

Arrow functions inherits this from their enclosing scope.
Safe fix: Use this instead of an alias.

(lint/complexity/noUselessThisAlias)

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🔭 Outside diff range comments (1)
assets/js-templates/form-components.php (1)

Line range hint 1655-1655: Remove console.log statement

Debug logging should not be present in production code.

-console.log(this.field_settings[field].pro_feature);
♻️ Duplicate comments (1)
assets/js/wpuf-form-builder-components.js (1)

777-782: 🛠️ Refactor suggestion

Enhance accessibility for custom dropdown implementation

The custom dropdown implementation should include ARIA attributes and keyboard navigation support for better accessibility.

🧹 Nitpick comments (11)
assets/js/wpuf-form-builder-mixins.js (3)

52-57: Consider enhancing button accessibility.

The button classes provide good visual feedback, but consider adding ARIA attributes and focus states for better accessibility.

 computed: {
     action_button_classes: function() {
-        return 'wpuf-p-2 hover:wpuf-cursor-pointer hover:wpuf-text-white';
+        return 'wpuf-p-2 hover:wpuf-cursor-pointer hover:wpuf-text-white focus:wpuf-outline-none focus:wpuf-ring-2 focus:wpuf-ring-offset-2 focus:wpuf-ring-primary';
     }
 },

95-125: Refactor class management to reduce complexity and improve maintainability.

While the implementation works, consider these improvements:

  1. The use of !important (!wpuf-border-gray-300) suggests potential CSS specificity issues.
  2. Common classes between field types could be extracted to reduce duplication.

Consider extracting common classes and using a configuration object:

const COMMON_CLASSES = {
  base: 'wpuf-block wpuf-rounded-md wpuf-text-gray-900 sm:wpuf-text-sm sm:wpuf-leading-6',
  input: 'wpuf-py-1.5 wpuf-shadow-sm wpuf-border wpuf-border-gray-300'
};

const FIELD_CLASSES = {
  upload_btn: `file-selector ${COMMON_CLASSES.base} wpuf-btn-secondary`,
  radio: 'wpuf-ml-3 wpuf-block wpuf-text-sm wpuf-font-medium wpuf-leading-6 wpuf-text-gray-900',
  // ... other field types
};

builder_class_names: function(type_class) {
  const fieldClasses = FIELD_CLASSES[type_class] || `${COMMON_CLASSES.base} ${COMMON_CLASSES.input}`;
  return [
    type_class,
    this.required_class(),
    'wpuf_' + this.field.name + '_' + this.form_id,
    fieldClasses
  ];
}

312-312: LGTM! Consider standardizing default prop values.

The change correctly implements Vue.js best practices. For consistency, consider extracting these default values into a shared configuration.

const DEFAULT_PROP = () => ({ key: 'value' });

// Usage in components
props: {
  field: {
    type: Object,
    default: DEFAULT_PROP
  },
  option_field: {
    type: Object,
    default: DEFAULT_PROP
  },
  editing_form_field: {
    type: Object,
    default: DEFAULT_PROP
  }
}
includes/Admin/Forms/Admin_Form_Builder.php (1)

266-271: Consider pagination for scalability.

The query retrieves all forms without pagination, which could impact performance if there are many forms.

Consider adding pagination or limiting the number of forms:

-$forms = get_posts([
-    'post_type'   => $post_type,
-    'post_status' => 'any',
-]);
+$forms = get_posts([
+    'post_type'   => $post_type,
+    'post_status' => 'any',
+    'posts_per_page' => 10,
+    'paged'         => max(1, get_query_var('paged')),
+]);
wpuf-functions.php (2)

4819-4829: Extract the version constant or inline documentation reference.

The doc block references @since WPUF_SINCE. Typically, you want to replace WPUF_SINCE with an actual version constant or a valid version number (e.g., 4.1.0) to accurately track when the function was introduced.

 /**
- * @since WPUF_SINCE
+ * @since 4.1.0 (Replace with the actual version)
  *
  * @return string
  */

4819-4829: Ensure unit test coverage.

This function is straightforward and not likely to fail under normal conditions, but a unit test that verifies the return string for different plugin states (e.g., when WPUF_ASSET_URI might differ) can be beneficial.

Do you want me to provide a basic unit test snippet to confirm the correct return value under various plugin asset configuration scenarios?

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

585-585: Simplify boolean ternary

You’re using a ternary that could be simplified:

- this.is_form_switcher = (this.is_form_switcher) ? false : true;
+ this.is_form_switcher = !this.is_form_switcher;
🧰 Tools
🪛 Biome (1.9.4)

[error] 585-585: Unnecessary use of boolean literals in conditional expression.

Simplify your code by directly assigning the result without using a ternary operator.
If your goal is negation, you may use the logical NOT (!) or double NOT (!!) operator for clearer and concise code.
Check for more details about NOT operator.
Unsafe fix: Remove the conditional expression with

(lint/complexity/noUselessTernary)

assets/js/wpuf-form-builder.js (3)

44-46: Enhance state initialization with TypeScript interfaces

The new state properties lack type definitions which could lead to potential runtime errors. Consider adding TypeScript interfaces to improve type safety and code maintainability.

+ interface FormBuilderState {
+   is_older_form: boolean;
+   is_post_form: boolean;
+   // ... other state properties
+ }

 state: {
-    is_older_form: wpuf_form_builder.is_older_form,
-    is_post_form: wpuf_form_builder.is_older_form && wpuf_form_builder.post.post_type === 'wpuf_forms',
+    is_older_form: wpuf_form_builder.is_older_form as boolean,
+    is_post_form: (wpuf_form_builder.is_older_form && wpuf_form_builder.post.post_type === 'wpuf_forms') as boolean,

Line range hint 93-108: Optimize field settings mutation with debouncing

The open_field_settings mutation uses a setTimeout which could cause unnecessary re-renders if triggered rapidly. Consider implementing debouncing to optimize performance.

+ const debounce = (fn, delay) => {
+   let timeoutId;
+   return (...args) => {
+     clearTimeout(timeoutId);
+     timeoutId = setTimeout(() => fn.apply(this, args), delay);
+   };
+ };

 open_field_settings: function(state, field_id) {
-    setTimeout(function() {
+    const debouncedUpdate = debounce(function() {
         state.editing_field_id = field[0].id;
-    }, 400);
+    }, 400);
+    debouncedUpdate();
 }

519-524: Add confirmation dialog for unsaved changes

The onbeforeunload handler should provide a more descriptive message and consider checking for specific changes rather than a generic dirty flag.

 window.onbeforeunload = function() {
-    if (self.isDirty) {
-        return self.i18n.unsaved_changes;
+    if (self.hasUnsavedChanges()) {
+        return self.i18n.unsaved_changes_message || 'You have unsaved changes. Are you sure you want to leave?';
     }
 };

+ methods: {
+    hasUnsavedChanges: function() {
+        return this.isDirty && this.form_fields.some(field => field.isModified);
+    }
+ }
assets/js-templates/form-components.php (1)

85-91: Improve empty state messaging and accessibility

The empty state messaging should be more descriptive and include proper ARIA attributes for screen readers.

-<div v-if="!form_fields.length" class="wpuf-flex wpuf-flex-col wpuf-items-center wpuf-justify-center wpuf-h-[80vh]">
+<div 
+    v-if="!form_fields.length" 
+    class="wpuf-flex wpuf-flex-col wpuf-items-center wpuf-justify-center wpuf-h-[80vh]"
+    role="status"
+    aria-live="polite"
+>
     <img 
         src="<?php echo WPUF_ASSET_URI . '/images/form-blank-state.svg'; ?>" 
+        alt="Empty form illustration"
+        role="presentation"
     >
-    <h2 class="wpuf-text-lg wpuf-text-gray-800"><?php esc_html_e('Add fields and build your desired form', 'wp-user-frontend'); ?></h2>
+    <h2 class="wpuf-text-lg wpuf-text-gray-800"><?php esc_html_e('Start Building Your Form', 'wp-user-frontend'); ?></h2>
-    <p class="wpuf-text-sm wpuf-text-gray-500"><?php esc_html_e('Add fields and build your desired form', 'wp-user-frontend'); ?></p>
+    <p class="wpuf-text-sm wpuf-text-gray-500"><?php esc_html_e('Drag and drop fields from the right panel to start building your form', 'wp-user-frontend'); ?></p>
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 579dba6 and 4b65706.

⛔ Files ignored due to path filters (2)
  • assets/images/minus-circle-green.svg is excluded by !**/*.svg
  • assets/images/plus-circle-green.svg is excluded by !**/*.svg
📒 Files selected for processing (19)
  • admin/form-builder/assets/js/components/builder-stage-v4-1/index.js (1 hunks)
  • admin/form-builder/assets/js/components/builder-stage-v4-1/template.php (1 hunks)
  • admin/form-builder/assets/js/components/builder-stage/index.js (1 hunks)
  • admin/form-builder/assets/js/components/form-dropdown_field/template.php (1 hunks)
  • admin/form-builder/assets/js/components/form-fields-v4-1/index.js (1 hunks)
  • admin/form-builder/assets/js/components/form-fields-v4-1/template.php (1 hunks)
  • admin/form-builder/assets/js/components/form-section_break/template.php (1 hunks)
  • admin/form-builder/assets/js/form-builder.js (13 hunks)
  • admin/form-builder/assets/js/mixins/form-field.js (3 hunks)
  • admin/form-builder/assets/less/form-builder.less (1 hunks)
  • admin/form-builder/views/form-builder-v4.1.php (1 hunks)
  • assets/css/wpuf-form-builder.css (1 hunks)
  • assets/js-templates/form-components.php (16 hunks)
  • assets/js/wpuf-form-builder-components.js (14 hunks)
  • assets/js/wpuf-form-builder-mixins.js (5 hunks)
  • assets/js/wpuf-form-builder.js (13 hunks)
  • includes/Admin/Forms/Admin_Form_Builder.php (4 hunks)
  • languages/wp-user-frontend.pot (36 hunks)
  • wpuf-functions.php (2 hunks)
✅ Files skipped from review due to trivial changes (1)
  • assets/css/wpuf-form-builder.css
🚧 Files skipped from review as they are similar to previous changes (8)
  • admin/form-builder/assets/js/components/builder-stage/index.js
  • admin/form-builder/assets/js/components/form-dropdown_field/template.php
  • admin/form-builder/assets/js/components/form-section_break/template.php
  • admin/form-builder/assets/js/components/builder-stage-v4-1/template.php
  • admin/form-builder/assets/less/form-builder.less
  • admin/form-builder/views/form-builder-v4.1.php
  • admin/form-builder/assets/js/components/form-fields-v4-1/template.php
  • admin/form-builder/assets/js/mixins/form-field.js
🧰 Additional context used
🪛 Biome (1.9.4)
admin/form-builder/assets/js/components/form-fields-v4-1/index.js

[error] 83-83: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

assets/js/wpuf-form-builder-components.js

[error] 332-332: Unnecessary use of boolean literals in conditional expression.

Simplify your code by directly assigning the result without using a ternary operator.
If your goal is negation, you may use the logical NOT (!) or double NOT (!!) operator for clearer and concise code.
Check for more details about NOT operator.
Unsafe fix: Remove the conditional expression with

(lint/complexity/noUselessTernary)


[error] 332-332: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 355-355: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 363-363: Unnecessary use of boolean literals in conditional expression.

Simplify your code by directly assigning the result without using a ternary operator.
If your goal is negation, you may use the logical NOT (!) or double NOT (!!) operator for clearer and concise code.
Check for more details about NOT operator.
Unsafe fix: Remove the conditional expression with

(lint/complexity/noUselessTernary)


[error] 301-301: This aliasing of this is unnecessary.

Arrow functions inherits this from their enclosing scope.
Safe fix: Use this instead of an alias.

(lint/complexity/noUselessThisAlias)


[error] 1630-1630: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

assets/js/wpuf-form-builder.js

[error] 585-585: Unnecessary use of boolean literals in conditional expression.

Simplify your code by directly assigning the result without using a ternary operator.
If your goal is negation, you may use the logical NOT (!) or double NOT (!!) operator for clearer and concise code.
Check for more details about NOT operator.
Unsafe fix: Remove the conditional expression with

(lint/complexity/noUselessTernary)

admin/form-builder/assets/js/form-builder.js

[error] 585-585: Unnecessary use of boolean literals in conditional expression.

Simplify your code by directly assigning the result without using a ternary operator.
If your goal is negation, you may use the logical NOT (!) or double NOT (!!) operator for clearer and concise code.
Check for more details about NOT operator.
Unsafe fix: Remove the conditional expression with

(lint/complexity/noUselessTernary)

admin/form-builder/assets/js/components/builder-stage-v4-1/index.js

[error] 145-145: Unnecessary use of boolean literals in conditional expression.

Simplify your code by directly assigning the result without using a ternary operator.
If your goal is negation, you may use the logical NOT (!) or double NOT (!!) operator for clearer and concise code.
Check for more details about NOT operator.
Unsafe fix: Remove the conditional expression with

(lint/complexity/noUselessTernary)


[error] 145-145: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 168-168: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 176-176: Unnecessary use of boolean literals in conditional expression.

Simplify your code by directly assigning the result without using a ternary operator.
If your goal is negation, you may use the logical NOT (!) or double NOT (!!) operator for clearer and concise code.
Check for more details about NOT operator.
Unsafe fix: Remove the conditional expression with

(lint/complexity/noUselessTernary)


[error] 114-114: This aliasing of this is unnecessary.

Arrow functions inherits this from their enclosing scope.
Safe fix: Use this instead of an alias.

(lint/complexity/noUselessThisAlias)

🔇 Additional comments (84)
assets/js/wpuf-form-builder-mixins.js (2)

68-68: LGTM! Important Vue.js best practice implemented.

Changing the prop default from an object to a function prevents shared state between component instances. This is crucial for avoiding unintended side effects where multiple instances modify the same default object.


307-307: LGTM! Consistent with Vue.js best practices.

The change to a function-based default value prevents shared state between component instances.

includes/Admin/Forms/Admin_Form_Builder.php (5)

129-129: LGTM! Added reCAPTCHA support.

Added 'recaptcha' to the list of single objects, which aligns with the existing 'cloudflare_turnstile' integration.


281-281: LGTM! Improved method documentation.

The documentation update clearly indicates that these are WordPress i18n translatable strings.


273-277: Verify template file existence.

The code conditionally includes different template files based on version, but doesn't verify if they exist.

Let's verify the template files:

✅ Verification successful

Template files verified and accessible

Both template files exist and are readable:

  • admin/form-builder/views/form-builder.php
  • admin/form-builder/views/form-builder-v4.1.php
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if both template files exist
echo "Checking form builder template files:"
ls -l admin/form-builder/views/form-builder.php admin/form-builder/views/form-builder-v4.1.php 2>/dev/null || echo "One or more template files missing"

Length of output: 370


166-174: Verify the version-specific feature flags.

The new localization keys support version-specific features:

  • is_older_form checks for Pro version < 4.1
  • is_pro_active determines if Pro is active
  • Added paths for loading assets from both free and pro versions

Let's verify the version checks are used consistently:

✅ Verification successful

Version-specific feature flags are properly implemented and consistent

The version checks and feature flags are implemented consistently across the codebase:

  • Version comparisons uniformly check for WPUF Pro < 4.1
  • The is_older_form flag is properly utilized in the form builder UI
  • Asset paths are correctly configured with appropriate constant checks
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for version comparison usage to ensure consistent version checking
echo "Searching for WPUF_PRO_VERSION comparisons:"
rg "version_compare\s*\(\s*WPUF_PRO_VERSION" -t php

echo -e "\nSearching for is_older_form usage in JS:"
rg "is_older_form" -g "*.{js,vue}"

Length of output: 3061


51-51: Verify the usage of the new action hook.

A new action hook wpuf_admin_form_builder_view has been added alongside the existing wpuf_admin_form_builder hook. Both hooks trigger the same callback method.

Let's check if both hooks are necessary:

✅ Verification successful

The new action hook implementation is correct

The hook wpuf_admin_form_builder_view is part of a form builder revamp and is properly implemented with version-based conditional logic to maintain backward compatibility with WPUF Pro versions below 4.1.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for usages of both hooks to understand if they serve different purposes
echo "Searching for wpuf_admin_form_builder hook usage:"
rg "do_action\s*\(\s*['\"]wpuf_admin_form_builder['\"]" -t php

echo -e "\nSearching for wpuf_admin_form_builder_view hook usage:"
rg "do_action\s*\(\s*['\"]wpuf_admin_form_builder_view['\"]" -t php

Length of output: 552


Script:

#!/bin/bash
# View the content of post-form.php to understand the context of both hooks
echo "Content of includes/Admin/views/post-form.php:"
cat includes/Admin/views/post-form.php

Length of output: 410

wpuf-functions.php (1)

4831-4840: Valid approach to detect the pro class.

This check using class_exists( 'WP_User_Frontend_Pro' ) is a good approach to verify if the commercial version is active. A fallback or more robust detection (like checking constants) might be worth considering if you foresee multiple Pro classes or differences in naming.

languages/wp-user-frontend.pot (37)

1-11: No Functional Impact on Code Execution

These lines update header metadata (year, creation date, revision date), which doesn't affect the plugin's logic. The changes appear consistent with updated release info.


Line range hint 139-151: Added or modified text strings are well-formed

The new strings and modifications follow consistent structure, appear grammatically correct, and do not pose i18n concerns.


167-171: Localized text updates

These placeholder strings for form import functionality remain consistent with the plugin’s pattern. No issues.


Line range hint 175-240: Metadata and additional placeholders

All placeholders and updated lines are properly formatted. No conflict with default text domain usage.


243-267: Concise improvements on message strings

The new placeholders for "Show values," "Sync values," "Label," etc. are properly introduced. No concerns.


275-282: Addition of more strings referencing advanced fields

Strings like "Clear Selection" and "Available in PRO version" align with typical premium gating. Good approach.


285-293: No i18n or PII issues

Text updates for subscription plan references do not expose personal data.


300-318: Search features and form idea submission placeholders

Proper English usage, consistent instructions for UI. No further changes needed.


320-365: Additional form editor instructions

These lines introduce new text for "Insert Photo," "Invisible reCaptcha," "Enable Multistep," etc. Implementation matches expected user guidance.


369-388: New blocks for UI feedback (Preview, Save Form)

Well-structured additions. Localization is consistent across the plugin.


Line range hint 468-559: Payment configuration text changes

No syntax or localizability issues. The gating for "Enable Payments" lines is correct.


Line range hint 617-637: User permissions & unsubscribed user messages

Strings for user permissions and unsubscribed states appear straightforward and help user clarity.


Line range hint 716-879: New placeholders for name, email, and instructions

These additions are carefully structured. No code logic concerns since POT changes have no direct functional effect.


978-1038: Enhanced error & success message strings

Localization-friendly approach for error dialogues.


Line range hint 1042-1162: Broader plugin coverage with new lines

Adds more messages for reCaptcha, image uploads, subscription details, plus general instructions. Everything looks correct.


Line range hint 1376-1434: Extended placeholders for form components

Ensures users see relevant instructions for textareas and advanced fields.


Line range hint 1455-1485: Capturing extended info for captcha & turnstile

Nicely integrated new references. No translation or variable collisions found.


Line range hint 1620-1639: Payment cancel & summary lines

Structure follows previous patterns, with placeholders for dynamic data. Good approach.


Line range hint 1770-1809: Post Expiration & advanced subscription lines

Integrates new lines seamlessly. No red flags spotted.


2241-2245: Added welcome message & instructions

Reference to a specialized user journey. Maintains uniform plugin tone.


2517-2538: New labeling for post form settings

No errors or style conflicts. This is consistent with other form references.


2543-2559: Ensuring form must have title/body fields

Business logic string influences front-end validation instructions. Looks fine.


2563-2609: Pro gating message expansions

Accurate gating instructions for Pro features. Seamless user experience.


Line range hint 2613-2669: User guidance for advanced custom fields

Text instructs user about ACF compatibility. Aligned well with the plugin's extended logic.


2670-2683: Integration request strings

Straightforward placeholders for custom integration requests.


305-310: Minor additions for template selection

No content or structural issues found.


3067-3093: Modal instructions for new form creation

Confirming i18n placeholders appear correct.


Line range hint 3176-3213: Advanced fields references

The expansions for “Google Map,” "Action Hook," "Address Field," etc. are consistent with prior text.


Line range hint 4353-4482: Cloudflare turnstile integration text

Added lines supporting new captcha method. Polished approach with well-formed instructions.


4490-4493: Column number, spacing info

Complements the new column field features. All good.


4553-4561: Section break references

No concerns. The lines remain consistent with existing structure.


4606-4614: URL field enhancements

"Open in new window" text updated for clarity. Good job.


4619-4631: Phone field & embed placeholders

No functional or typographical problems.


4635-4656: Pro upgrade references

Keeps marketing and gating consistent. No duplication.


4661-4679: Multi-step, math captcha, QR code coverage

No concerns. Straight to the point.


6109-6110: New placeholders for marking items featured

Implementation matches the plugin’s existing approach to labeling.


7892-7947: Enhanced select messages (accessibility)

Introduces clarity for screen readers. Good for user experience.

admin/form-builder/assets/js/components/form-fields-v4-1/index.js (15)

1-3: Clear self-documentation in the header comment

Indicates purpose of the new Vue component for the sidebar form fields.


4-6: Component registration

Defines the 'form-fields-v4-1' component, no issues with naming.


7-8: Mixins usage is correct

Successfully merges wpuf_form_builder_mixins and add_form_field functionalities.


9-13: Data properties initialization

The searched_fields and is_pro_active properties are clearly set, indicating user’s search input and pro status.


16-28: Computed properties referencing Vuex

panel_sections, field_settings, form_fields are well structured. No duplication found.


30-50: Draggable initialization in mounted hook

Draggable is re-bound after destroying previous instances. This prevents potential double-binding issues. Good job.


52-55: Method: panel_toggle

Commits a Vuex mutation to toggle panel sections. Straightforward, no concerns.


57-59: Method: is_pro_feature

Checks if a field is gated for pro. Implementation is direct and consistent with field settings.


61-78: Method: alert_pro_feature

Provides a sweet alert if a field is pro-only. Clear logic, no problem.


80-93: Method: alert_invalidate_msg

Displays warnings if the field_settings validator has a message. The approach is robust.

🧰 Tools
🪛 Biome (1.9.4)

[error] 83-83: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


95-97: Method: get_invalidate_btn_class

Simple method returning CSS classes for the validator button.


99-101: Method: set_default_panel_sections

Commits mutation to restore panel sections to default. Good separation of concerns.


103-115: Method: get_icon_url

Provides correct icon path depending on pro status or normal. The debug log is helpful for verifying.


117-121: Method: is_pro_preview

Prevents preview unless pro is active. Straightforward gating logic.


124-165: Watch: searched_fields

Resets the default panel sections upon text changes, re-initializes drag behavior, then filters fields. Implementation is robust and user-friendly.

admin/form-builder/assets/js/components/builder-stage-v4-1/index.js (11)

1-3: Component definition & template reference

Registers 'builder-stage-v4-1' correctly, referencing the correct template ID.


4-5: Mixins for builder_stage & add_form_field

Appropriate usage merges relevant functionalities.


6-28: Computed properties referencing Vuex store

Retrieves form_fields, field_settings, and others. Implementation is consistent with the overall store.


30-82: mounted hook – jQuery UI sortable setup

Sort functionality is properly configured. The logic for detecting drag from panel vs stage is well-handled with source.


84-88: Method: open_field_settings

Commits Vuex mutation to open field settings. This matches the typical structure in WP User Frontend.


89-111: Method: clone_field

Clones existing field if not single-instance. Thorough check with simple user feedback using SweetAlert. Works well.


113-132: Method: delete_field

Prompts the user for confirmation before removing. Proper use of SweetAlert for user safety.

🧰 Tools
🪛 Biome (1.9.4)

[error] 114-114: This aliasing of this is unnecessary.

Arrow functions inherits this from their enclosing scope.
Safe fix: Use this instead of an alias.

(lint/complexity/noUselessThisAlias)


134-142: Method: delete_hidden_field

Iterates known fields for matching ID and calls delete_field. Straightforward approach.


144-146: Method: is_pro_feature

Checks pro_feature property from field_settings. Good gating.

🧰 Tools
🪛 Biome (1.9.4)

[error] 145-145: Unnecessary use of boolean literals in conditional expression.

Simplify your code by directly assigning the result without using a ternary operator.
If your goal is negation, you may use the logical NOT (!) or double NOT (!!) operator for clearer and concise code.
Check for more details about NOT operator.
Unsafe fix: Remove the conditional expression with

(lint/complexity/noUselessTernary)


[error] 145-145: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


148-165: Method: is_template_available, is_full_width, is_invisible, get_field_name

Ensures correct field availability checks and UI decisions. Implementation looks consistent.


167-183: No extra logic concerns

The file ends with consistent usage of these methods. Everything is well-coded.

🧰 Tools
🪛 Biome (1.9.4)

[error] 168-168: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 176-176: Unnecessary use of boolean literals in conditional expression.

Simplify your code by directly assigning the result without using a ternary operator.
If your goal is negation, you may use the logical NOT (!) or double NOT (!!) operator for clearer and concise code.
Check for more details about NOT operator.
Unsafe fix: Remove the conditional expression with

(lint/complexity/noUselessTernary)

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

44-46: New state properties: is_older_form, is_post_form

These boolean flags help differentiate older vs. newer form logic. Great approach for backward compatibility.


47-47: current_panel initialization

Switches between 'form-fields' and 'form-fields-v4-1' based on form type. Nicely decoupled.


73-73: Reset editing_field_id for new panel names

Ensures a clean state when toggling the main panel. Zero side effects seen.


Line range hint 93-108: open_field_settings mutation

Brief wait with setTimeout to ensure the correct field is assigned after switching panels. No concurrency issues.


245-245: delete_form_field_element mutation

Resets current panel to 'form-fields' or 'form-fields-v4-1' after deletion. A well-defined fallback.


392-392: delete_column_field_element mutation

Similarly toggles the panel upon deleting a column field. Maintains state consistency.


396-399: Mutation: set_panel_sections

Updates state with new panel sections, possibly used by the new v4-1 panel. Straightforward approach.


401-404: Mutation: set_default_panel_sections

Resets panel sections to defaults from global object. Smooth addition.


423-424: New data flags: isDirty

Helps track unsaved changes. Implementation aligns with typical form builder logic.


425-426: New data flags: enableMultistep, shortcodeCopied

Used to manage multi-step toggle and user feedback for copied shortcodes. No concerns.


427-428: Active Tab management

active_tab, active_settings_tab track user’s current view. Straightforward.


466-466: Computed property: meta_field_key

Filters form fields to retrieve meta fields. Implementation is correct, no performance issues.


600-601: Set current panel to fallback before form submission

Switching panel ensures correct state prior to saving.

Comment on lines +489 to +517
var clipboard = new window.Clipboard('.form-id');
var settings_tabs = $( '#wpuf-form-builder-settings-tabs .nav-tab' );
var self = this;

// secondary settings tabs and their contents
var settings_tabs = $('#wpuf-form-builder-settings .nav-tab'),
settings_tab_contents = $('#wpuf-form-builder-settings .tab-contents .group');
$(".form-id").tooltip();

settings_tabs.first().addClass('nav-tab-active');
settings_tab_contents.first().addClass('active');
if ( this.is_post_form ) {
// add a click listener to each settings_tab
settings_tabs.each( function () {
$( this ).bind( 'click', self.setActiveSettingsTab );
} );

clipboard.on( 'success', function ( e ) {
// Show copied tooltip
$( e.trigger )
.attr( 'data-original-title', 'Shortcode copied!' )
.tooltip( 'show' );

self.shortcodeCopied = true;

// Reset the copied tooltip
setTimeout( function () {
$( e.trigger ).tooltip( 'hide' )
.attr( 'data-original-title', self.i18n.copy_shortcode );
self.shortcodeCopied = false;
}, 1000 );

e.clearSelection();
} );
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Improve clipboard initialization and error handling

The clipboard initialization lacks error handling and cleanup. Consider adding error handling and proper cleanup in the component's beforeDestroy lifecycle hook.

 mounted: function() {
-    var clipboard = new window.Clipboard('.form-id');
+    try {
+        this.clipboard = new window.Clipboard('.form-id');
+        this.initializeClipboard();
+    } catch (error) {
+        console.error('Failed to initialize clipboard:', error);
+    }
 },

+ beforeDestroy: function() {
+    if (this.clipboard) {
+        this.clipboard.destroy();
+    }
+ },

+ methods: {
+    initializeClipboard: function() {
+        if (!this.clipboard) return;
         
+        this.clipboard.on('success', (e) => {
             // ... existing clipboard success handler
+        }).on('error', (e) => {
+            console.error('Action:', e.action);
+            console.error('Trigger:', e.trigger);
+        });
+    }
+ }

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

Comment on lines 188 to 370
methods: {
open_field_settings: function(field_id) {
this.$store.commit('open_field_settings', field_id);
},

clone_field: function(field_id, index) {
var payload = {
field_id: field_id,
index: index,
new_id: this.get_random_id()
};

// single instance checking
var field = _.find(this.$store.state.form_fields, function (item) {
return parseInt(item.id) === parseInt(payload.field_id);
});

// check if these are already inserted
if ( this.isSingleInstance( field.template ) && this.containsField( field.template ) ) {
Swal.fire({
title: "Oops...",
text: "You already have this field in the form"
});
return;
}

this.$store.commit('clone_form_field_element', payload);
},

delete_field: function(index) {
var self = this;

(Swal.fire({
text: self.i18n.delete_field_warn_msg,
icon: 'warning',
showCancelButton: true,
confirmButtonColor: '#d54e21',
confirmButtonText: self.i18n.yes_delete_it,
cancelButtonText: self.i18n.no_cancel_it,
customClass: {
confirmButton: 'btn btn-success',
cancelButton: 'btn btn-danger',
}
})).then((result) => {
if (result.isConfirmed) {
self.$store.commit('delete_form_field_element', index);
}
});
},

delete_hidden_field: function (field_id) {
var i = 0;

for (i = 0; i < this.form_fields.length; i++) {
if (parseInt(field_id) === parseInt(this.form_fields[i].id)) {
this.delete_field(i);
}
}
},

is_pro_feature: function (template) {
return ( this.field_settings[template] && this.field_settings[template].pro_feature ) ? true : false;
},

is_template_available: function (field) {
var template = field.template;

if (this.field_settings[template]) {
if (this.is_pro_feature(template)) {
return false;
}

return true;
}

// for example see 'mixin_builder_stage' mixin's 'is_taxonomy_template_available' method
if (_.isFunction(this['is_' + template + '_template_available'])) {
return this['is_' + template + '_template_available'].call(this, field);
}

return false;
},

is_full_width: function (template) {
if (this.field_settings[template] && this.field_settings[template].is_full_width) {
return true;
}

return false;
},

is_invisible: function (field) {
return ( field.recaptcha_type && 'invisible_recaptcha' === field.recaptcha_type ) ? true : false;
},

get_field_name: function (template) {
return this.field_settings[template].title;
}
}
});
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Enhance component reusability and reduce code duplication

The builder-stage-v4-1 component largely duplicates code from the original builder-stage component. Consider extracting common functionality into a mixin or base component.

+ const builderStageMixin = {
+   computed: {
+     form_fields() { ... },
+     field_settings() { ... },
+     hidden_fields() { ... },
+     editing_form_id() { ... },
+     pro_link() { ... }
+   },
+   methods: {
+     open_field_settings() { ... },
+     clone_field() { ... },
+     delete_field() { ... }
+   }
+ };

 Vue.component('builder-stage-v4-1', {
   template: '#tmpl-wpuf-builder-stage-v4-1',
-  // Duplicate code
+  mixins: [builderStageMixin],
   // Component-specific code
 });

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

🧰 Tools
🪛 Biome (1.9.4)

[error] 332-332: Unnecessary use of boolean literals in conditional expression.

Simplify your code by directly assigning the result without using a ternary operator.
If your goal is negation, you may use the logical NOT (!) or double NOT (!!) operator for clearer and concise code.
Check for more details about NOT operator.
Unsafe fix: Remove the conditional expression with

(lint/complexity/noUselessTernary)


[error] 332-332: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 355-355: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 363-363: Unnecessary use of boolean literals in conditional expression.

Simplify your code by directly assigning the result without using a ternary operator.
If your goal is negation, you may use the logical NOT (!) or double NOT (!!) operator for clearer and concise code.
Check for more details about NOT operator.
Unsafe fix: Remove the conditional expression with

(lint/complexity/noUselessTernary)


[error] 301-301: This aliasing of this is unnecessary.

Arrow functions inherits this from their enclosing scope.
Safe fix: Use this instead of an alias.

(lint/complexity/noUselessThisAlias)

Comment on lines +1471 to +1480
<span
class="field-helper-text wpuf-ml-2"
:data-placement="placement"
data-toggle="tooltip"
data-container="body">
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" fill="none">
<path d="M9.833 12.333H9V9h-.833M9 5.667h.008M16.5 9a7.5 7.5 0 1 1-15 0 7.5 7.5 0 1 1 15 0z"
stroke="#9CA3AF" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path>
</svg>
</span>
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Enhance tooltip accessibility

The help text tooltip implementation should include proper ARIA attributes and keyboard interaction support.

 <span
     class="field-helper-text wpuf-ml-2"
     :data-placement="placement"
-    data-toggle="tooltip"
+    role="tooltip"
+    :aria-label="text"
+    tabindex="0"
+    @keydown.enter="toggleTooltip"
+    @keydown.space="toggleTooltip"
     data-container="body">
     <svg 
         xmlns="http://www.w3.org/2000/svg" 
         width="18" 
         height="18" 
         fill="none"
+        role="img"
+        aria-hidden="true"
     >

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

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (12)
assets/js/wpuf-form-builder-mixins.js (2)

59-62: Consider extracting CSS classes to a configuration object.

While the implementation works, consider moving these Tailwind CSS classes to a configuration object for better maintainability and reusability across components.

+ const ACTION_BUTTON_CLASSES = 'wpuf-p-2 hover:wpuf-cursor-pointer hover:wpuf-text-white';
  computed: {
    action_button_classes: function() {
-     return 'wpuf-p-2 hover:wpuf-cursor-pointer hover:wpuf-text-white';
+     return ACTION_BUTTON_CLASSES;
    }
  },

Line range hint 1-1: Consider gradual migration from jQuery to pure Vue.js.

While the current implementation works, the mixture of jQuery and Vue.js could lead to maintenance challenges. Consider planning a gradual migration to pure Vue.js for better maintainability and performance.

admin/form-builder/assets/js/mixins/add-form-field.js (1)

49-53: Simplify the code using optional chaining.

The function can be simplified for better readability.

Apply this diff to improve the code:

-        is_pro_preview: function (template) {
-            var is_pro_active = wpuf_form_builder.is_pro_active === '1';
-
-            return (!is_pro_active && this.field_settings[template] && this.field_settings[template].pro_feature);
-        },
+        is_pro_preview: function (template) {
+            return wpuf_form_builder.is_pro_active !== '1' && this.field_settings[template]?.pro_feature;
+        },
admin/form-builder/assets/js/components/form-fields-v4-1/index.js (1)

103-113: Simplify the code using early return pattern.

The method can be simplified for better readability.

Apply this diff to improve the code:

-        get_icon_url: function (field) {
-            if (!this.field_settings[field].icon) {
-                return '';
-            }
-
-            if (this.is_pro_active === '1' && this.field_settings[field].pro_feature) {
-                return wpuf_form_builder.pro_asset_url + '/images/' + this.field_settings[field].icon + '.svg';
-            } else {
-                return wpuf_form_builder.asset_url + '/images/' + this.field_settings[field].icon + '.svg';
-            }
-        },
+        get_icon_url: function (field) {
+            const icon = this.field_settings[field]?.icon;
+            if (!icon) {
+                return '';
+            }
+            const baseUrl = (this.is_pro_active === '1' && this.field_settings[field].pro_feature)
+                ? wpuf_form_builder.pro_asset_url
+                : wpuf_form_builder.asset_url;
+            return `${baseUrl}/images/${icon}.svg`;
+        },
admin/form-builder/assets/js/components/builder-stage-v4-1/index.js (2)

144-146: Simplify boolean expression.

The method uses an unnecessary ternary operator and could benefit from optional chaining.

Apply this diff to improve the code:

-        is_pro_feature: function (template) {
-            return (this.field_settings[template] && this.field_settings[template].pro_feature) ? true : false;
-        },
+        is_pro_feature: function (template) {
+            return Boolean(this.field_settings[template]?.pro_feature);
+        },
🧰 Tools
🪛 Biome (1.9.4)

[error] 145-145: Unnecessary use of boolean literals in conditional expression.

Simplify your code by directly assigning the result without using a ternary operator.
If your goal is negation, you may use the logical NOT (!) or double NOT (!!) operator for clearer and concise code.
Check for more details about NOT operator.
Unsafe fix: Remove the conditional expression with

(lint/complexity/noUselessTernary)


[error] 145-145: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


175-177: Simplify boolean expression.

The method uses an unnecessary ternary operator.

Apply this diff to improve the code:

-        is_invisible: function (field) {
-            return ( field.recaptcha_type && 'invisible_recaptcha' === field.recaptcha_type ) ? true : false;
-        },
+        is_invisible: function (field) {
+            return field.recaptcha_type === 'invisible_recaptcha';
+        },
🧰 Tools
🪛 Biome (1.9.4)

[error] 176-176: Unnecessary use of boolean literals in conditional expression.

Simplify your code by directly assigning the result without using a ternary operator.
If your goal is negation, you may use the logical NOT (!) or double NOT (!!) operator for clearer and concise code.
Check for more details about NOT operator.
Unsafe fix: Remove the conditional expression with

(lint/complexity/noUselessTernary)

admin/form-builder/assets/js/components/form-column_field/template.php (1)

1-126: Extract repeated class combinations into computed properties.

The template has several repeated class combinations that could be extracted into computed properties for better maintainability.

Add these computed properties to the component:

computed: {
    columnWrapperClasses() {
        return 'wpuf-flex-1 wpuf-min-w-0 wpuf-min-h-full wpuf-column-inner-fields';
    },
    columnContainerClasses() {
        return 'wpuf-border wpuf-border-dashed wpuf-border-green-400 wpuf-bg-green-50 wpuf-shadow-sm wpuf-rounded-md wpuf-p-1';
    },
    columnItemClasses() {
        return '!wpuf-m-0 !wpuf-p-0 wpuf-group/column-inner hover:wpuf-bg-green-50 wpuf-transition wpuf-duration-150 wpuf-ease-out column-field-items wpuf-el wpuf-rounded-t-md';
    }
}

Then update the template:

-    class="wpuf-flex-1 wpuf-min-w-0 wpuf-min-h-full wpuf-column-inner-fields">
+    :class="columnWrapperClasses">

-    class="wpuf-border wpuf-border-dashed wpuf-border-green-400 wpuf-bg-green-50 wpuf-shadow-sm wpuf-rounded-md wpuf-p-1">
+    :class="columnContainerClasses">

-    class="!wpuf-m-0 !wpuf-p-0 wpuf-group/column-inner hover:wpuf-bg-green-50 wpuf-transition wpuf-duration-150 wpuf-ease-out column-field-items wpuf-el wpuf-rounded-t-md"
+    :class="[columnItemClasses, ...]"
admin/form-builder/assets/js/components/form-column_field/index.js (1)

121-130: Simplify array generation using Array.from.

The computed property can be simplified using Array.from for better readability.

Apply this diff to improve the code:

-        columnClasses: function() {
-            var columns_count = parseInt( this.field.columns );
-            var columns = [];
-
-            for (var i = 1; i <= columns_count; i++) {
-                columns.push('column-' + i);
-            }
-
-            return columns;
-        }
+        columnClasses: function() {
+            const columns_count = parseInt(this.field.columns);
+            return Array.from(
+                { length: columns_count },
+                (_, i) => `column-${i + 1}`
+            );
+        }
admin/form-builder/assets/js/components/builder-stage-v4-1/template.php (3)

2-6: Differentiate heading and description text for better UX

The same text is used for both the heading and description, which doesn't provide additional value to users.

 <div v-if="!form_fields.length" class="wpuf-flex wpuf-flex-col wpuf-items-center wpuf-justify-center wpuf-h-[80vh]">
     <img src="<?php echo WPUF_ASSET_URI . '/images/form-blank-state.svg'; ?>" alt="">
     <h2 class="wpuf-text-lg wpuf-text-gray-800"><?php esc_html_e( 'Add fields and build your desired form', 'wp-user-frontend' ); ?></h2>
-    <p class="wpuf-text-sm wpuf-text-gray-500"><?php esc_html_e( 'Add fields and build your desired form', 'wp-user-frontend' ); ?></p>
+    <p class="wpuf-text-sm wpuf-text-gray-500"><?php esc_html_e( 'Drag and drop fields from the right sidebar to start building your form', 'wp-user-frontend' ); ?></p>
 </div>

8-120: Enhance accessibility for form field controls

While the implementation is solid, the form field controls could benefit from improved accessibility.

 <div
     v-if="field.input_type !== 'column_field'"
     :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-4 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">
+    class="wpuf-flex wpuf-justify-between wpuf-p-4 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"
+    role="group"
+    :aria-label="field.label + ' field controls'">

     <!-- Control buttons -->
     <span
         :class="action_button_classes"
-        @click="open_field_settings(field.id)">
+        @click="open_field_settings(field.id)"
+        role="button"
+        tabindex="0"
+        :aria-label="'Edit ' + field.label"
+        @keydown.enter="open_field_settings(field.id)">
         <i class="fa fa-pencil"></i>
         Edit
     </span>

125-193: Extract control buttons into a reusable component

The control buttons logic is duplicated between regular form fields and hidden fields. Consider extracting this into a reusable component to improve maintainability and reduce code duplication.

Create a new component field-control-buttons.php:

<template>
  <div class="field-buttons" :class="buttonClasses">
    <div class="wpuf-flex wpuf-justify-around wpuf-text-green-200">
      <template v-if="!is_failed_to_validate(field.template)">
        <span v-if="showMove" :class="action_button_classes">
          <i class="fa fa-arrows move wpuf-pr-2 wpuf-rounded-l-md hover:!wpuf-cursor-move wpuf-border-r wpuf-border-green-200"></i>
        </span>
        <span :class="action_button_classes" @click="$emit('edit', field.id)">
          <i class="fa fa-pencil"></i> Edit
        </span>
        <span :class="action_button_classes" @click="$emit('clone', field.id, index)">
          <i class="fa fa-clone"></i> Copy
        </span>
      </template>
      <!-- ... rest of the control buttons ... -->
    </div>
  </div>
</template>

<script>
export default {
  props: {
    field: Object,
    index: Number,
    showMove: {
      type: Boolean,
      default: true
    },
    buttonClasses: Object
  }
}
</script>

Then use it in both places:

- <div class="field-buttons">...</div>
+ <field-control-buttons
+   :field="field"
+   :index="index"
+   :show-move="true"
+   :button-classes="buttonClasses"
+   @edit="open_field_settings"
+   @clone="clone_field"
+   @delete="delete_field"
+ />
assets/js/wpuf-form-builder-components.js (1)

376-377: Document mixin usage and purpose

Multiple components have been updated to include form_field_mixin, but its purpose and provided functionality are not documented.

Add JSDoc comments to explain the mixin's purpose and usage:

/**
 * Provides common form field functionality
 * @mixin
 * @description This mixin provides common methods and computed properties for form fields
 * @example
 * // In a component:
 * export default {
 *   mixins: [wpuf_mixins.form_field_mixin],
 *   // ... component logic
 * }
 */
const form_field_mixin = {
  // ... mixin implementation
};

Also consider adding inline documentation where the mixin is used:

 Vue.component('field-checkbox', {
     template: '#tmpl-wpuf-field-checkbox',
 
     mixins: [
         wpuf_mixins.option_field_mixin,
+        // Provides common form field validation and styling
         wpuf_mixins.form_field_mixin
     ],

Also applies to: 476-477, 805-806, 876-877, 897-898

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4b65706 and ad480f8.

📒 Files selected for processing (9)
  • admin/form-builder/assets/js/components/builder-stage-v4-1/index.js (1 hunks)
  • admin/form-builder/assets/js/components/builder-stage-v4-1/template.php (1 hunks)
  • admin/form-builder/assets/js/components/form-column_field/index.js (3 hunks)
  • admin/form-builder/assets/js/components/form-column_field/template.php (1 hunks)
  • admin/form-builder/assets/js/components/form-fields-v4-1/index.js (1 hunks)
  • admin/form-builder/assets/js/mixins/add-form-field.js (1 hunks)
  • assets/js-templates/form-components.php (16 hunks)
  • assets/js/wpuf-form-builder-components.js (14 hunks)
  • assets/js/wpuf-form-builder-mixins.js (5 hunks)
🧰 Additional context used
🪛 Biome (1.9.4)
assets/js/wpuf-form-builder-components.js

[error] 332-332: Unnecessary use of boolean literals in conditional expression.

Simplify your code by directly assigning the result without using a ternary operator.
If your goal is negation, you may use the logical NOT (!) or double NOT (!!) operator for clearer and concise code.
Check for more details about NOT operator.
Unsafe fix: Remove the conditional expression with

(lint/complexity/noUselessTernary)


[error] 332-332: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 355-355: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 363-363: Unnecessary use of boolean literals in conditional expression.

Simplify your code by directly assigning the result without using a ternary operator.
If your goal is negation, you may use the logical NOT (!) or double NOT (!!) operator for clearer and concise code.
Check for more details about NOT operator.
Unsafe fix: Remove the conditional expression with

(lint/complexity/noUselessTernary)


[error] 301-301: This aliasing of this is unnecessary.

Arrow functions inherits this from their enclosing scope.
Safe fix: Use this instead of an alias.

(lint/complexity/noUselessThisAlias)


[error] 1630-1630: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

admin/form-builder/assets/js/components/builder-stage-v4-1/index.js

[error] 145-145: Unnecessary use of boolean literals in conditional expression.

Simplify your code by directly assigning the result without using a ternary operator.
If your goal is negation, you may use the logical NOT (!) or double NOT (!!) operator for clearer and concise code.
Check for more details about NOT operator.
Unsafe fix: Remove the conditional expression with

(lint/complexity/noUselessTernary)


[error] 145-145: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 168-168: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 176-176: Unnecessary use of boolean literals in conditional expression.

Simplify your code by directly assigning the result without using a ternary operator.
If your goal is negation, you may use the logical NOT (!) or double NOT (!!) operator for clearer and concise code.
Check for more details about NOT operator.
Unsafe fix: Remove the conditional expression with

(lint/complexity/noUselessTernary)


[error] 114-114: This aliasing of this is unnecessary.

Arrow functions inherits this from their enclosing scope.
Safe fix: Use this instead of an alias.

(lint/complexity/noUselessThisAlias)

admin/form-builder/assets/js/components/form-fields-v4-1/index.js

[error] 83-83: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

🔇 Additional comments (7)
assets/js/wpuf-form-builder-mixins.js (4)

51-57: LGTM! Well-implemented pro feature check.

The is_pro_preview method effectively determines if a field template is a pro feature while the pro version is inactive.


73-75: LGTM! Important Vue.js best practice implementation.

Changing the prop's default value to a factory function prevents shared state issues between component instances, which is crucial for maintaining proper component isolation.


312-314: LGTM! Consistent prop initialization.

Good practice using a factory function for the prop's default value, maintaining consistency with Vue.js best practices.


317-319: LGTM! Proper prop initialization.

Correctly implements Vue.js best practice for prop default values using a factory function.

admin/form-builder/assets/js/mixins/add-form-field.js (1)

57-59: LGTM!

The computed property correctly returns Tailwind CSS classes for consistent button styling across the form builder.

admin/form-builder/assets/js/components/form-column_field/index.js (1)

117-119: LGTM!

The computed property correctly returns Tailwind CSS classes for consistent button styling across the form builder.

assets/js-templates/form-components.php (1)

1043-1171: 🛠️ Refactor suggestion

Enhance accessibility for form field search and buttons

The new form fields panel needs improved keyboard navigation and screen reader support.

 <div class="wpuf-px-6">
     <div class="wpuf-flex wpuf-rounded-lg wpuf-bg-white wpuf-outline wpuf--outline-1 wpuf--outline-offset-1 wpuf-outline-gray-300 wpuf-border wpuf-border-gray-200 wpuf-shadow">
         <input
             type="text"
             name="search"
             id="search"
             v-model="searched_fields"
+            aria-label="Search form fields"
+            role="searchbox"
             class="!wpuf-border-none !wpuf-rounded-lg wpuf-block wpuf-min-w-0 wpuf-grow wpuf-px-4 wpuf-py-1.5 wpuf-text-base wpuf-text-gray-900 placeholder:wpuf-text-gray-400 sm:wpuf-text-sm/6 !wpuf-shadow-none !wpuf-ring-transparent"
             placeholder="<?php esc_attr_e( 'Search Field', 'wp-user-frontend' ); ?>">
         <div class="wpuf-flex wpuf-py-1.5 wpuf-pr-1.5">
             <span class="wpuf-inline-flex wpuf-items-center wpuf-rounded wpuf-px-1 wpuf-font-sans wpuf-text-xs wpuf-text-gray-400">
                 <svg
                     v-if="!searched_fields"
                     xmlns="http://www.w3.org/2000/svg"
                     fill="none"
                     viewBox="0 0 24 24"
                     stroke-width="1.5"
                     stroke="currentColor"
+                    role="img"
+                    aria-label="Search"
                     class="wpuf-size-5 hover:wpuf-cursor-pointer wpuf-transition-all">
                     <path stroke-linecap="round" stroke-linejoin="round" d="m21 21-5.197-5.197m0 0A7.5 7.5 0 1 0 5.196 5.196a7.5 7.5 0 0 0 10.607 10.607Z" />
                 </svg>
                 <svg
                     v-if="searched_fields"
                     @click="searched_fields = ''"
+                    @keydown.enter="searched_fields = ''"
+                    tabindex="0"
+                    role="button"
+                    aria-label="Clear search"
                     xmlns="http://www.w3.org/2000/svg"
                     viewBox="0 0 20 20"
                     fill="currentColor"
                     class="wpuf-size-5 hover:wpuf-cursor-pointer wpuf-transition-all">
                     <path d="M6.28 5.22a.75.75 0 0 0-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 1 0 1.06 1.06L10 11.06l3.72 3.72a.75.75 0 1 0 1.06-1.06L11.06 10l3.72-3.72a.75.75 0 0 0-1.06-1.06L10 8.94 6.28 5.22Z" />
                 </svg>
             </span>
         </div>
     </div>
     <!-- Field buttons -->
     <div
         v-else
         :key="field"
         :data-form-field="field"
         data-source="panel"
         @click="add_form_field(field)"
+        @keydown.enter="add_form_field(field)"
+        tabindex="0"
+        role="button"
+        :aria-label="'Add ' + field_settings[field].title + ' field'"
         class="wpuf-field-button wpuf-relative wpuf-flex wpuf-items-center wpuf-rounded-lg wpuf-border wpuf-border-gray-200 wpuf-bg-white wpuf-shadow-sm wpuf-p-3 hover:wpuf-border-gray-300 hover:wpuf-cursor-pointer">
         <!-- ... button content ... -->
     </div>

Likely invalid or redundant comment.

Comment on lines 101 to 131
builder_class_names: function(type_class) {
var commonClasses = '';

switch (type_class) {
case 'upload_btn':
commonClasses = 'file-selector wpuf-rounded-md wpuf-btn-secondary';
break;

case 'radio':
commonClasses = 'wpuf-ml-3 wpuf-block wpuf-text-sm wpuf-font-medium wpuf-leading-6 wpuf-text-gray-900';
break;

case 'checkbox':
commonClasses = 'wpuf-h-4 wpuf-w-4 wpuf-rounded wpuf-border-gray-300 !wpuf-mt-0.5 checked:focus:wpuf-bg-primary checked:hover:wpuf-bg-primary checked:wpuf-bg-primary before:!wpuf-content-none';
break;

case 'dropdown':
commonClasses = 'wpuf-block wpuf-w-full wpuf-min-w-full wpuf-rounded-md wpuf-py-1.5 wpuf-text-gray-900 wpuf-shadow-sm placeholder:wpuf-text-gray-400 sm:wpuf-text-sm sm:wpuf-leading-6 wpuf-border !wpuf-border-gray-300';
break;

default:
commonClasses = 'wpuf-block wpuf-min-w-full wpuf-rounded-md wpuf-py-1.5 wpuf-text-gray-900 !wpuf-shadow-sm placeholder:wpuf-text-gray-400 sm:wpuf-text-sm sm:wpuf-leading-6 wpuf-border !wpuf-border-gray-300 wpuf-max-w-full';
}

return [
type_class,
this.required_class(),
'wpuf_' + this.field.name + '_' + this.form_id,
commonClasses
];
},
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Refactor class generation for better maintainability.

The current implementation could be improved in several ways:

  1. Extract CSS classes to a configuration object
  2. Add input validation
  3. Remove duplicate classes
+ const FIELD_CLASSES = {
+   base: 'wpuf-block wpuf-rounded-md wpuf-py-1.5 wpuf-text-gray-900 wpuf-shadow-sm',
+   common: 'placeholder:wpuf-text-gray-400 sm:wpuf-text-sm sm:wpuf-leading-6',
+   upload_btn: 'file-selector wpuf-rounded-md wpuf-btn-secondary',
+   radio: 'wpuf-ml-3 wpuf-block wpuf-text-sm wpuf-font-medium wpuf-leading-6 wpuf-text-gray-900',
+   checkbox: 'wpuf-h-4 wpuf-w-4 wpuf-rounded wpuf-border-gray-300 !wpuf-mt-0.5',
+   dropdown: 'wpuf-block wpuf-w-full wpuf-min-w-full'
+ };

  builder_class_names: function(type_class) {
+   if (!type_class || typeof type_class !== 'string') {
+     console.warn('Invalid type_class provided to builder_class_names');
+     return [];
+   }
+   
    var commonClasses = '';
    
-   switch (type_class) {
-     case 'upload_btn':
-       commonClasses = 'file-selector  wpuf-rounded-md wpuf-btn-secondary';
-       break;
-     // ... other cases
+   commonClasses = FIELD_CLASSES[type_class] || FIELD_CLASSES.base;
+   commonClasses += ' ' + FIELD_CLASSES.common;

    return [
      type_class,
      this.required_class(),
      'wpuf_' + this.field.name + '_' + this.form_id,
      commonClasses
    ];
  },

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

Comment on lines +117 to +157
searched_fields: function ( searchValue ) {
var self = this;

this.set_default_panel_sections();

// Bind jquery ui draggable. But first destroy any previous binding
Vue.nextTick(function () {
var buttons = $(self.$el).find('.panel-form-field-buttons .wpuf-field-button');

buttons.each(function () {

if ($(this).draggable('instance')) {
$(this).draggable('destroy');
}
});

buttons.draggable({
connectToSortable: '#form-preview-stage, #form-preview-stage .wpuf-form, .wpuf-column-inner-fields .wpuf-column-fields-sortable-list',
helper: 'clone',
revert: 'invalid',
cancel: '.button-faded',
}).disableSelection();
});

if (this.searched_fields === '') {
return;
}

const matchedFields = Object.keys( self.field_settings ).filter( key =>
self.field_settings[key].title.toLowerCase().includes( searchValue.toLowerCase() )
);

const updatedStructure = self.panel_sections.map(section => ({
id: section.id,
title: section.title,
show: section.show,
fields: section.fields.filter(field => matchedFields.includes(field))
}));

this.$store.commit('set_panel_sections', updatedStructure);
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Refactor to reduce code duplication and improve readability.

The watcher duplicates draggable initialization code from the mounted hook and could benefit from simpler filtering logic.

  1. Extract draggable initialization to a separate method:
methods: {
    initializeDraggable: function() {
        const buttons = $(this.$el).find('.panel-form-field-buttons .wpuf-field-button');
        
        buttons.each(function() {
            if ($(this).draggable('instance')) {
                $(this).draggable('destroy');
            }
        });
        
        buttons.draggable({
            connectToSortable: '#form-preview-stage, #form-preview-stage .wpuf-form, .wpuf-column-inner-fields .wpuf-column-fields-sortable-list',
            helper: 'clone',
            revert: 'invalid',
            cancel: '.button-faded',
        }).disableSelection();
    }
}
  1. Simplify the watcher:
-        searched_fields: function ( searchValue ) {
-            var self = this;
-
-            this.set_default_panel_sections();
-
-            // Bind jquery ui draggable. But first destroy any previous binding
-            Vue.nextTick(function () {
-                var buttons = $(self.$el).find('.panel-form-field-buttons .wpuf-field-button');
-
-                buttons.each(function () {
-
-                    if ($(this).draggable('instance')) {
-                        $(this).draggable('destroy');
-                    }
-                });
-
-                buttons.draggable({
-                    connectToSortable: '#form-preview-stage, #form-preview-stage .wpuf-form, .wpuf-column-inner-fields .wpuf-column-fields-sortable-list',
-                    helper: 'clone',
-                    revert: 'invalid',
-                    cancel: '.button-faded',
-                }).disableSelection();
-            });
-
-            if (this.searched_fields === '') {
-                return;
-            }
-
-            const matchedFields = Object.keys( self.field_settings ).filter( key =>
-                self.field_settings[key].title.toLowerCase().includes( searchValue.toLowerCase() )
-            );
-
-            const updatedStructure = self.panel_sections.map(section => ({
-                id: section.id,
-                title: section.title,
-                show: section.show,
-                fields: section.fields.filter(field => matchedFields.includes(field))
-            }));
-
-            this.$store.commit('set_panel_sections', updatedStructure);
-        }
+        searched_fields: function(searchValue) {
+            this.set_default_panel_sections();
+            
+            Vue.nextTick(() => {
+                this.initializeDraggable();
+            });
+            
+            if (!searchValue) {
+                return;
+            }
+            
+            const searchLower = searchValue.toLowerCase();
+            const matchedFields = new Set(
+                Object.entries(this.field_settings)
+                    .filter(([_, field]) => field.title.toLowerCase().includes(searchLower))
+                    .map(([key]) => key)
+            );
+            
+            const updatedStructure = this.panel_sections.map(section => ({
+                ...section,
+                fields: section.fields.filter(field => matchedFields.has(field))
+            }));
+            
+            this.$store.commit('set_panel_sections', updatedStructure);
+        }

Comment on lines 188 to 370
methods: {
open_field_settings: function(field_id) {
this.$store.commit('open_field_settings', field_id);
},

clone_field: function(field_id, index) {
var payload = {
field_id: field_id,
index: index,
new_id: this.get_random_id()
};

// single instance checking
var field = _.find(this.$store.state.form_fields, function (item) {
return parseInt(item.id) === parseInt(payload.field_id);
});

// check if these are already inserted
if ( this.isSingleInstance( field.template ) && this.containsField( field.template ) ) {
Swal.fire({
title: "Oops...",
text: "You already have this field in the form"
});
return;
}

this.$store.commit('clone_form_field_element', payload);
},

delete_field: function(index) {
var self = this;

(Swal.fire({
text: self.i18n.delete_field_warn_msg,
icon: 'warning',
showCancelButton: true,
confirmButtonColor: '#d54e21',
confirmButtonText: self.i18n.yes_delete_it,
cancelButtonText: self.i18n.no_cancel_it,
customClass: {
confirmButton: 'btn btn-success',
cancelButton: 'btn btn-danger',
}
})).then((result) => {
if (result.isConfirmed) {
self.$store.commit('delete_form_field_element', index);
}
});
},

delete_hidden_field: function (field_id) {
var i = 0;

for (i = 0; i < this.form_fields.length; i++) {
if (parseInt(field_id) === parseInt(this.form_fields[i].id)) {
this.delete_field(i);
}
}
},

is_pro_feature: function (template) {
return ( this.field_settings[template] && this.field_settings[template].pro_feature ) ? true : false;
},

is_template_available: function (field) {
var template = field.template;

if (this.field_settings[template]) {
if (this.is_pro_preview(template)) {
return false;
}

return true;
}

// for example see 'mixin_builder_stage' mixin's 'is_taxonomy_template_available' method
if (_.isFunction(this['is_' + template + '_template_available'])) {
return this['is_' + template + '_template_available'].call(this, field);
}

return false;
},

is_full_width: function (template) {
if (this.field_settings[template] && this.field_settings[template].is_full_width) {
return true;
}

return false;
},

is_invisible: function (field) {
return ( field.recaptcha_type && 'invisible_recaptcha' === field.recaptcha_type ) ? true : false;
},

get_field_name: function (template) {
return this.field_settings[template].title;
}
}
});
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Optimize code quality and reduce duplication

The new builder-stage-v4-1 component has several code quality issues and duplicates much of the original builder-stage component's logic.

  1. Remove unnecessary this aliasing:
-        var self = this;
         (Swal.fire({
-            text: self.i18n.delete_field_warn_msg,
+            text: this.i18n.delete_field_warn_msg,
             icon: 'warning',
             showCancelButton: true,
             confirmButtonColor: '#d54e21',
-            confirmButtonText: self.i18n.yes_delete_it,
-            cancelButtonText: self.i18n.no_cancel_it,
+            confirmButtonText: this.i18n.yes_delete_it,
+            cancelButtonText: this.i18n.no_cancel_it,
             customClass: {
                 confirmButton: 'btn btn-success',
                 cancelButton: 'btn btn-danger',
             }
         })).then((result) => {
             if (result.isConfirmed) {
-                self.$store.commit('delete_form_field_element', index);
+                this.$store.commit('delete_form_field_element', index);
             }
         });
  1. Simplify boolean expressions:
-        return (this.field_settings[template] && this.field_settings[template].pro_feature) ? true : false;
+        return !!(this.field_settings[template] && this.field_settings[template].pro_feature);
  1. Extract common logic into a mixin:
// form-builder-stage-mixin.js
export const formBuilderStageMixin = {
  methods: {
    open_field_settings(field_id) {
      this.$store.commit('open_field_settings', field_id);
    },
    clone_field(field_id, index) {
      // ... common clone logic
    },
    delete_field(index) {
      // ... common delete logic
    }
    // ... other common methods
  }
};

// In component
{
  mixins: [formBuilderStageMixin],
  // Component-specific logic
}
🧰 Tools
🪛 Biome (1.9.4)

[error] 332-332: Unnecessary use of boolean literals in conditional expression.

Simplify your code by directly assigning the result without using a ternary operator.
If your goal is negation, you may use the logical NOT (!) or double NOT (!!) operator for clearer and concise code.
Check for more details about NOT operator.
Unsafe fix: Remove the conditional expression with

(lint/complexity/noUselessTernary)


[error] 332-332: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 355-355: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 363-363: Unnecessary use of boolean literals in conditional expression.

Simplify your code by directly assigning the result without using a ternary operator.
If your goal is negation, you may use the logical NOT (!) or double NOT (!!) operator for clearer and concise code.
Check for more details about NOT operator.
Unsafe fix: Remove the conditional expression with

(lint/complexity/noUselessTernary)


[error] 301-301: This aliasing of this is unnecessary.

Arrow functions inherits this from their enclosing scope.
Safe fix: Use this instead of an alias.

(lint/complexity/noUselessThisAlias)

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

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

101-131: 🛠️ Refactor suggestion

Refactor class generation for better maintainability.

The current implementation could benefit from the previously suggested refactoring approach to improve maintainability and reduce duplication.

See the previous review comment for the detailed refactoring suggestion that extracts CSS classes to a configuration object.

assets/js-templates/form-components.php (1)

1454-1463: 🛠️ Refactor suggestion

Enhance tooltip accessibility.

The help text tooltip implementation should include proper ARIA attributes and keyboard interaction support.

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

52-56: Consider using strict boolean comparison.

The string comparison with '1' could be replaced with a more explicit boolean check.

-            var is_pro_active = wpuf_form_builder.is_pro_active === '1';
+            var is_pro_active = Boolean(parseInt(wpuf_form_builder.is_pro_active, 10));
assets/js-templates/form-components.php (1)

918-918: Standardize help text styling across components.

The help text styling is inconsistent across different form field components. Some use <span> while others use <p>, and the classes are not consistently applied.

Standardize the help text implementation:

-<span v-if="field.help" class="wpuf-help" v-html="field.help"></span>
+<p v-if="field.help" class="wpuf-mt-2 wpuf-text-sm wpuf-text-gray-500" v-html="field.help"></p>

Also applies to: 938-938, 951-951, 974-974, 1183-1183, 1252-1252, 1267-1267, 1281-1281, 1318-1318, 1403-1403, 1416-1416, 1436-1436, 1449-1449

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

188-370: Consider extracting common logic to reduce duplication

The builder-stage-v4-1 component largely duplicates code from the original builder-stage component. Consider extracting shared functionality into a mixin or base component to improve maintainability.

+ const builderStageMixin = {
+   computed: {
+     form_fields() { ... },
+     field_settings() { ... },
+     hidden_fields() { ... },
+     editing_form_id() { ... },
+     pro_link() { ... }
+   },
+   methods: {
+     open_field_settings() { ... },
+     clone_field() { ... },
+     delete_field() { ... }
+   }
+ };

 Vue.component('builder-stage-v4-1', {
   template: '#tmpl-wpuf-builder-stage-v4-1',
+  mixins: [builderStageMixin],
   // Component-specific code
 });
🧰 Tools
🪛 Biome (1.9.4)

[error] 332-332: Unnecessary use of boolean literals in conditional expression.

Simplify your code by directly assigning the result without using a ternary operator.
If your goal is negation, you may use the logical NOT (!) or double NOT (!!) operator for clearer and concise code.
Check for more details about NOT operator.
Unsafe fix: Remove the conditional expression with

(lint/complexity/noUselessTernary)


[error] 332-332: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 355-355: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 363-363: Unnecessary use of boolean literals in conditional expression.

Simplify your code by directly assigning the result without using a ternary operator.
If your goal is negation, you may use the logical NOT (!) or double NOT (!!) operator for clearer and concise code.
Check for more details about NOT operator.
Unsafe fix: Remove the conditional expression with

(lint/complexity/noUselessTernary)


[error] 301-301: This aliasing of this is unnecessary.

Arrow functions inherits this from their enclosing scope.
Safe fix: Use this instead of an alias.

(lint/complexity/noUselessThisAlias)


332-332: Simplify boolean expressions

The ternary operators for boolean conversion can be simplified.

-            return (this.field_settings[template] && this.field_settings[template].pro_feature) ? true : false;
+            return !!(this.field_settings[template] && this.field_settings[template].pro_feature);

-            return (field.recaptcha_type && 'invisible_recaptcha' === field.recaptcha_type) ? true : false;
+            return !!(field.recaptcha_type && 'invisible_recaptcha' === field.recaptcha_type);

Also applies to: 363-363

🧰 Tools
🪛 Biome (1.9.4)

[error] 332-332: Unnecessary use of boolean literals in conditional expression.

Simplify your code by directly assigning the result without using a ternary operator.
If your goal is negation, you may use the logical NOT (!) or double NOT (!!) operator for clearer and concise code.
Check for more details about NOT operator.
Unsafe fix: Remove the conditional expression with

(lint/complexity/noUselessTernary)


[error] 332-332: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

admin/form-builder/assets/js/components/builder-stage-v4-1/index.js (4)

1-4: Consider local component registration and SFC pattern.

The current implementation uses global component registration and external templates. Consider:

  1. Using local component registration for better tree-shaking
  2. Moving to Single File Components (SFC) pattern for better maintainability
  3. Documenting mixin dependencies to prevent naming conflicts

21-23: Fix naming inconsistency in computed property.

The computed property editing_form_id accesses editing_field_id from the store. Align the naming to prevent confusion.

-    editing_form_id: function () {
-        return this.$store.state.editing_field_id;
+    editing_field_id: function () {
+        return this.$store.state.editing_field_id;

144-146: Optimize boolean expressions and method implementations.

Several methods can be simplified:

 is_pro_feature: function (template) {
-    return ( this.field_settings[template] && this.field_settings[template].pro_feature ) ? true : false;
+    return Boolean(this.field_settings[template]?.pro_feature);
 },

 is_full_width: function (template) {
-    if (this.field_settings[template] && this.field_settings[template].is_full_width) {
-        return true;
-    }
-    return false;
+    return Boolean(this.field_settings[template]?.is_full_width);
 },

 is_invisible: function (field) {
-    return ( field.recaptcha_type && 'invisible_recaptcha' === field.recaptcha_type ) ? true : false;
+    return field.recaptcha_type === 'invisible_recaptcha';
 },

Also applies to: 167-173, 175-177

🧰 Tools
🪛 Biome (1.9.4)

[error] 145-145: Unnecessary use of boolean literals in conditional expression.

Simplify your code by directly assigning the result without using a ternary operator.
If your goal is negation, you may use the logical NOT (!) or double NOT (!!) operator for clearer and concise code.
Check for more details about NOT operator.
Unsafe fix: Remove the conditional expression with

(lint/complexity/noUselessTernary)


[error] 145-145: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


113-132: Simplify delete_field method using arrow function.

The method uses unnecessary this aliasing. Modern JavaScript allows cleaner implementation:

 delete_field: function(index) {
-    var self = this;
-
     (Swal.fire({
-        text: self.i18n.delete_field_warn_msg,
+        text: this.i18n.delete_field_warn_msg,
         icon: 'warning',
         showCancelButton: true,
         confirmButtonColor: '#d54e21',
-        confirmButtonText: self.i18n.yes_delete_it,
-        cancelButtonText: self.i18n.no_cancel_it,
+        confirmButtonText: this.i18n.yes_delete_it,
+        cancelButtonText: this.i18n.no_cancel_it,
         customClass: {
             confirmButton: 'btn btn-success',
             cancelButton: 'btn btn-danger',
         }
-    })).then((result) => {
+    })).then(result => {
         if (result.isConfirmed) {
-            self.$store.commit('delete_form_field_element', index);
+            this.$store.commit('delete_form_field_element', index);
         }
     });
 },
🧰 Tools
🪛 Biome (1.9.4)

[error] 114-114: This aliasing of this is unnecessary.

Arrow functions inherits this from their enclosing scope.
Safe fix: Use this instead of an alias.

(lint/complexity/noUselessThisAlias)

admin/form-builder/assets/js/components/field-option-data/template.php (4)

2-6: Maintain consistency in help-text component usage.

The help text component is used with different prop patterns across the file. Consider standardizing the usage:

-<help-text v-if="option_field.help_text" :text="option_field.help_text"></help-text>
+<help-text 
+    v-if="option_field.help_text" 
+    :text="option_field.help_text"
+></help-text>

7-22: Enhance accessibility for checkbox controls.

Consider adding aria-label attributes and improving keyboard navigation:

 <input
     type="checkbox"
     v-model="show_value"
-    class="wpuf-input-checkbox">
+    class="wpuf-input-checkbox"
+    :aria-label="<?php esc_attr_e( 'Show values', 'wp-user-frontend' ); ?>"
+>

118-124: Enhance keyboard accessibility for clear selection button.

Add keyboard interaction attributes and role:

 <a
     v-if="!option_field.is_multiple && selected"
     class="wpuf-inline-flex wpuf-items-center wpuf-gap-x-2 wpuf-rounded-md wpuf-px-3 wpuf-py-2 wpuf-text-sm wpuf-text-gray-700  hover:wpuf-text-gray-700 hover:wpuf-bg-gray-50 wpuf-ring-1 wpuf-ring-inset wpuf-ring-gray-300 wpuf-mt-4"
     href="#clear"
+    role="button"
+    tabindex="0"
+    @keyup.enter="clear_selection"
     @click.prevent="clear_selection">

1-124: Consider extracting utility classes into component classes.

The extensive use of utility classes, while flexible, may lead to maintenance challenges. Consider:

  1. Creating reusable component classes for common patterns
  2. Using CSS modules or scoped styles for better encapsulation
  3. Implementing a design system for consistent styling

This would improve maintainability and reduce duplication across templates.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ad480f8 and 879ee1b.

📒 Files selected for processing (10)
  • admin/form-builder/assets/js/components/builder-stage-v4-1/index.js (1 hunks)
  • admin/form-builder/assets/js/components/builder-stage-v4-1/template.php (1 hunks)
  • admin/form-builder/assets/js/components/field-option-data/template.php (1 hunks)
  • admin/form-builder/assets/js/components/form-radio_field/template.php (1 hunks)
  • admin/form-builder/assets/js/mixins/form-field.js (3 hunks)
  • admin/form-builder/assets/less/form-builder.less (1 hunks)
  • assets/css/wpuf-form-builder.css (1 hunks)
  • assets/js-templates/form-components.php (16 hunks)
  • assets/js/wpuf-form-builder-components.js (14 hunks)
  • assets/js/wpuf-form-builder-mixins.js (5 hunks)
🚧 Files skipped from review as they are similar to previous changes (5)
  • admin/form-builder/assets/js/components/form-radio_field/template.php
  • assets/css/wpuf-form-builder.css
  • admin/form-builder/assets/js/mixins/form-field.js
  • admin/form-builder/assets/less/form-builder.less
  • admin/form-builder/assets/js/components/builder-stage-v4-1/template.php
🧰 Additional context used
🪛 Biome (1.9.4)
assets/js/wpuf-form-builder-components.js

[error] 332-332: Unnecessary use of boolean literals in conditional expression.

Simplify your code by directly assigning the result without using a ternary operator.
If your goal is negation, you may use the logical NOT (!) or double NOT (!!) operator for clearer and concise code.
Check for more details about NOT operator.
Unsafe fix: Remove the conditional expression with

(lint/complexity/noUselessTernary)


[error] 332-332: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 355-355: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 363-363: Unnecessary use of boolean literals in conditional expression.

Simplify your code by directly assigning the result without using a ternary operator.
If your goal is negation, you may use the logical NOT (!) or double NOT (!!) operator for clearer and concise code.
Check for more details about NOT operator.
Unsafe fix: Remove the conditional expression with

(lint/complexity/noUselessTernary)


[error] 301-301: This aliasing of this is unnecessary.

Arrow functions inherits this from their enclosing scope.
Safe fix: Use this instead of an alias.

(lint/complexity/noUselessThisAlias)


[error] 1630-1630: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

admin/form-builder/assets/js/components/builder-stage-v4-1/index.js

[error] 145-145: Unnecessary use of boolean literals in conditional expression.

Simplify your code by directly assigning the result without using a ternary operator.
If your goal is negation, you may use the logical NOT (!) or double NOT (!!) operator for clearer and concise code.
Check for more details about NOT operator.
Unsafe fix: Remove the conditional expression with

(lint/complexity/noUselessTernary)


[error] 145-145: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 168-168: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 176-176: Unnecessary use of boolean literals in conditional expression.

Simplify your code by directly assigning the result without using a ternary operator.
If your goal is negation, you may use the logical NOT (!) or double NOT (!!) operator for clearer and concise code.
Check for more details about NOT operator.
Unsafe fix: Remove the conditional expression with

(lint/complexity/noUselessTernary)


[error] 114-114: This aliasing of this is unnecessary.

Arrow functions inherits this from their enclosing scope.
Safe fix: Use this instead of an alias.

(lint/complexity/noUselessThisAlias)

🔇 Additional comments (11)
assets/js/wpuf-form-builder-mixins.js (4)

60-62: LGTM! Well-structured Tailwind classes.

The computed property provides a clean way to manage button styling using Tailwind CSS classes.


74-74: LGTM! Follows Vue.js best practices.

Using a factory function for the prop default prevents shared state between component instances, which is crucial for avoiding unintended mutations.


89-89: LGTM! Fixed syntax error.

The missing closing brace has been added, resolving the syntax error.


313-318: LGTM! Consistent prop defaults implementation.

The prop defaults are correctly implemented using factory functions, maintaining consistency with Vue.js best practices across the codebase.

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

41-41: LGTM: Updated selector aligns with new UI structure


376-377: LGTM: Enhanced component with form field mixin

Good addition of the form field mixin to share common functionality.


476-477: LGTM: Enhanced component with form field mixin

Good addition of the form field mixin to share common functionality.


610-610: LGTM: Enhanced component with form field mixin

Good addition of the form field mixin while maintaining existing functionality.


2063-2066: LGTM: Improved tooltip configuration

Enhanced tooltip initialization with dynamic title and auto placement.


1548-1706: LGTM: Well-implemented search functionality

The new form-fields-v4-1 component adds search capabilities with proper cleanup and reinitialization of jQuery UI bindings.

🧰 Tools
🪛 Biome (1.9.4)

[error] 1630-1630: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


301-301: 🛠️ Refactor suggestion

Remove unnecessary this aliasing

The var self = this pattern is unnecessary when using arrow functions as they preserve the lexical scope.

-            var self = this;
-
             (Swal.fire({
-                text: self.i18n.delete_field_warn_msg,
+                text: this.i18n.delete_field_warn_msg,
                 icon: 'warning',
                 showCancelButton: true,
                 confirmButtonColor: '#d54e21',
-                confirmButtonText: self.i18n.yes_delete_it,
-                cancelButtonText: self.i18n.no_cancel_it,
+                confirmButtonText: this.i18n.yes_delete_it,
+                cancelButtonText: this.i18n.no_cancel_it,

Likely invalid or redundant comment.

🧰 Tools
🪛 Biome (1.9.4)

[error] 301-301: This aliasing of this is unnecessary.

Arrow functions inherits this from their enclosing scope.
Safe fix: Use this instead of an alias.

(lint/complexity/noUselessThisAlias)

Comment on lines +148 to +165
<span :class="action_button_classes">
<i
class="fa fa-arrows move wpuf-pr-2 wpuf-rounded-l-md hover:!wpuf-cursor-move wpuf-border-r wpuf-border-green-200"></i>
</span>
<span
:class="action_button_classes"
@click="open_field_settings(field.id)">
<i
class="fa fa-pencil"></i>
Edit
</span>
<span
:class="action_button_classes"
@click="clone_field(field.id, index)">
<i
class="fa fa-clone"></i>
Copy
</span>
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Enhance accessibility of action buttons.

The action buttons lack proper ARIA labels and keyboard interaction support.

Add appropriate ARIA attributes and keyboard support:

 <span :class="action_button_classes">
     <i
-        class="fa fa-arrows move wpuf-pr-2 wpuf-rounded-l-md hover:!wpuf-cursor-move wpuf-border-r wpuf-border-green-200"></i>
+        class="fa fa-arrows move wpuf-pr-2 wpuf-rounded-l-md hover:!wpuf-cursor-move wpuf-border-r wpuf-border-green-200"
+        role="button"
+        tabindex="0"
+        aria-label="Move field"
+        @keydown.enter="handleMove"
+        @keydown.space="handleMove"></i>
 </span>
 <span
     :class="action_button_classes"
+    role="button"
+    tabindex="0"
     @click="open_field_settings(field.id)">
     <i
         class="fa fa-pencil"></i>
         Edit
 </span>

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

Comment on lines +34 to +81
// bind jquery ui sortable
$('#form-preview-stage, #form-preview-stage .wpuf-form.sortable-list').sortable({
placeholder: 'form-preview-stage-dropzone',
items: '.field-items',
handle: '.field-buttons .move',
scroll: true,
over: function() {
in_column_field = false;

// if the field drop in column field, then stop field rendering in the builder stage
$(".wpuf-column-inner-fields" ).on( "drop", function(event) {
var targetColumn = event.currentTarget.classList,
isColumnExist = $.inArray(".wpuf-column-inner-fields", targetColumn);

if ( isColumnExist ) {
in_column_field = true;
}
} );
},
update: function (e, ui) {
var item = ui.item[0],
data = item.dataset,
source = data.source,
toIndex = parseInt($(ui.item).index()),
payload = {
toIndex: toIndex
};

if ('panel' === source) {
// add new form element
self.$store.state.index_to_insert = parseInt(toIndex);

if ( ! in_column_field ) {
var field_template = ui.item[0].dataset.formField;
self.add_form_field(field_template);
}

// remove button from stage
$(this).find('.wpuf-field-button').remove();

} else if ('stage' === source) {
payload.fromIndex = parseInt(data.index);

self.$store.commit('swap_form_field_elements', payload);
}

}
});
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Improve jQuery UI integration with Vue.

Several concerns in the sortable implementation:

  1. Direct DOM manipulation with jQuery might conflict with Vue's virtual DOM
  2. Direct store state mutation (self.$store.state.index_to_insert) violates Vuex patterns
  3. Complex column field logic could be extracted into a separate method

Consider these improvements:

  1. Use Vue refs instead of jQuery selectors
  2. Move state mutations to Vuex mutations
  3. Extract column field logic to a dedicated method

Example refactor for the state mutation:

- self.$store.state.index_to_insert = parseInt(toIndex);
+ self.$store.commit('set_insert_index', parseInt(toIndex));

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

Comment on lines +24 to +115
<?php esc_attr_e( 'Label', 'wp-user-frontend' ); ?>
<help-text text="<?php esc_attr_e( 'Do not use & or other special character for option label', 'wp-user-frontend' ); ?>"></help-text>
</th>
<th
v-if="show_value"
class="wpuf-font-normal"
scope="col">
<?php esc_attr_e( 'Value', 'wp-user-frontend' ); ?>
</th>
<th scope="col"></th>
<th scope="col"></th>
</tr>
</thead>
<tbody>
<tr
v-for="(option, index) in options"
:key="option.id"
:data-index="index">
<td class="wpuf-flex">
<div class="selector ">
<input
v-if="option_field.is_multiple"
type="checkbox"
:value="option.value"
v-model="selected"
class="wpuf-input-checkbox"
>
<input
v-else
type="radio"
:value="option.value"
v-model="selected"
:class="builder_class_names('radio')"
>
</div>
<div class="sort-handler">
<i class="fa fa-bars"></i>
</div>
</td>
<td>
<input
type="checkbox"
v-model="show_value"
/><?php esc_attr_e( 'Show values', 'wp-user-frontend' ); ?>
</label>
</li>
<li>
<label>
:class="builder_class_names('text')"
type="text"
v-model="option.label"
@input="set_option_label(index, option.label)">
</td>
<td
v-if="show_value"
class="wpuf-text-sm wpuf-text-gray-500">
<input
type="checkbox"
v-model="sync_value"
/><?php esc_attr_e( 'Sync values', 'wp-user-frontend' ); ?>
</label>
<help-text placement="left" text="<?php esc_attr_e( 'When enabled, option values will update according to their labels.', 'wp-user-frontend' ); ?>" />
</li>
</ul>
:class="builder_class_names('text')"
type="text"
v-model="option.value">
</td>
<td class="wpuf-ml-2 wpuf-flex wpuf-items-center">
<div
class="action-buttons hover:wpuf-cursor-pointer wpuf-mt-1"
@click="delete_option(index)">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="wpuf-size-6 wpuf-border wpuf-rounded-2xl wpuf-border-gray-400 hover:wpuf-border-primary wpuf-p-1">
<path stroke-linecap="round" stroke-linejoin="round" d="M5 12h14" />
</svg>
</div>
<div
v-if="index === options.length - 1"
class="plus-buttons hover:wpuf-cursor-pointer !wpuf-border-0 wpuf-mt-1"
@click="add_option">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="wpuf-ml-1 wpuf-size-6 wpuf-border wpuf-rounded-2xl wpuf-border-gray-400 wpuf-p-1">
<path stroke-linecap="round" stroke-linejoin="round" d="M12 4.5v15m7.5-7.5h-15" />
</svg>
</div>
</td>
</tr>
</tbody>
</table>
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Improve table accessibility and security.

Several improvements are recommended:

  1. Add ARIA labels and roles to enhance table accessibility
  2. Implement input sanitization for option labels
  3. Consider extracting repeated utility classes into reusable CSS classes

Apply these changes:

-<table class="wpuf-w-full wpuf-text-left">
+<table 
+    class="wpuf-w-full wpuf-text-left"
+    role="grid"
+    aria-label="<?php esc_attr_e( 'Field options', 'wp-user-frontend' ); ?>"
+>

 <input
     :class="builder_class_names('text')"
     type="text"
     v-model="option.label"
-    @input="set_option_label(index, option.label)">
+    @input="set_option_label(index, $event.target.value)"
+    :aria-label="<?php esc_attr_e( 'Option label', 'wp-user-frontend' ); ?>"
+>

Also, consider extracting repeated utility classes like wpuf-border wpuf-rounded-2xl wpuf-border-gray-400 into a reusable CSS class.

📝 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
<div class="option-field-option-chooser wpuf-mx-auto wpuf-flow-root wpuf-overflow-hidden">
<table class="wpuf-w-full wpuf-text-left">
<thead class="wpuf-bg-white">
<tr>
<th scope="col"></th>
<th scope="col" class="wpuf-flex wpuf-font-normal">
<?php esc_attr_e( 'Label', 'wp-user-frontend' ); ?>
<help-text text="<?php esc_attr_e( 'Do not use & or other special character for option label', 'wp-user-frontend' ); ?>"></help-text>
</th>
<th
v-if="show_value"
class="wpuf-font-normal"
scope="col">
<?php esc_attr_e( 'Value', 'wp-user-frontend' ); ?>
</th>
<th scope="col"></th>
<th scope="col"></th>
</tr>
</thead>
<tbody>
<tr
v-for="(option, index) in options"
:key="option.id"
:data-index="index">
<td class="wpuf-flex">
<div class="selector ">
<input
v-if="option_field.is_multiple"
type="checkbox"
:value="option.value"
v-model="selected"
class="wpuf-input-checkbox"
>
<input
v-else
type="radio"
:value="option.value"
v-model="selected"
:class="builder_class_names('radio')"
>
</div>
<div class="sort-handler">
<i class="fa fa-bars"></i>
</div>
</td>
<td>
<input
type="checkbox"
v-model="show_value"
/><?php esc_attr_e( 'Show values', 'wp-user-frontend' ); ?>
</label>
</li>
<li>
<label>
:class="builder_class_names('text')"
type="text"
v-model="option.label"
@input="set_option_label(index, option.label)">
</td>
<td
v-if="show_value"
class="wpuf-text-sm wpuf-text-gray-500">
<input
type="checkbox"
v-model="sync_value"
/><?php esc_attr_e( 'Sync values', 'wp-user-frontend' ); ?>
</label>
<help-text placement="left" text="<?php esc_attr_e( 'When enabled, option values will update according to their labels.', 'wp-user-frontend' ); ?>" />
</li>
</ul>
:class="builder_class_names('text')"
type="text"
v-model="option.value">
</td>
<td class="wpuf-ml-2 wpuf-flex wpuf-items-center">
<div
class="action-buttons hover:wpuf-cursor-pointer wpuf-mt-1"
@click="delete_option(index)">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="wpuf-size-6 wpuf-border wpuf-rounded-2xl wpuf-border-gray-400 hover:wpuf-border-primary wpuf-p-1">
<path stroke-linecap="round" stroke-linejoin="round" d="M5 12h14" />
</svg>
</div>
<div
v-if="index === options.length - 1"
class="plus-buttons hover:wpuf-cursor-pointer !wpuf-border-0 wpuf-mt-1"
@click="add_option">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="wpuf-ml-1 wpuf-size-6 wpuf-border wpuf-rounded-2xl wpuf-border-gray-400 wpuf-p-1">
<path stroke-linecap="round" stroke-linejoin="round" d="M12 4.5v15m7.5-7.5h-15" />
</svg>
</div>
</td>
</tr>
</tbody>
</table>
<div class="option-field-option-chooser wpuf-mx-auto wpuf-flow-root wpuf-overflow-hidden">
<table
class="wpuf-w-full wpuf-text-left"
role="grid"
aria-label="<?php esc_attr_e( 'Field options', 'wp-user-frontend' ); ?>"
>
<thead class="wpuf-bg-white">
<tr>
<th scope="col"></th>
<th scope="col" class="wpuf-flex wpuf-font-normal">
<?php esc_attr_e( 'Label', 'wp-user-frontend' ); ?>
<help-text text="<?php esc_attr_e( 'Do not use & or other special character for option label', 'wp-user-frontend' ); ?>"></help-text>
</th>
<th
v-if="show_value"
class="wpuf-font-normal"
scope="col">
<?php esc_attr_e( 'Value', 'wp-user-frontend' ); ?>
</th>
<th scope="col"></th>
<th scope="col"></th>
</tr>
</thead>
<tbody>
<tr
v-for="(option, index) in options"
:key="option.id"
:data-index="index">
<td class="wpuf-flex">
<div class="selector ">
<input
v-if="option_field.is_multiple"
type="checkbox"
:value="option.value"
v-model="selected"
class="wpuf-input-checkbox"
>
<input
v-else
type="radio"
:value="option.value"
v-model="selected"
:class="builder_class_names('radio')"
>
</div>
<div class="sort-handler">
<i class="fa fa-bars"></i>
</div>
</td>
<td>
<input
:class="builder_class_names('text')"
type="text"
v-model="option.label"
@input="set_option_label(index, $event.target.value)"
:aria-label="<?php esc_attr_e( 'Option label', 'wp-user-frontend' ); ?>"
>
</td>
<td
v-if="show_value"
class="wpuf-text-sm wpuf-text-gray-500">
<input
:class="builder_class_names('text')"
type="text"
v-model="option.value">
</td>
<td class="wpuf-ml-2 wpuf-flex wpuf-items-center">
<div
class="action-buttons hover:wpuf-cursor-pointer wpuf-mt-1"
@click="delete_option(index)">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="wpuf-size-6 wpuf-border wpuf-rounded-2xl wpuf-border-gray-400 hover:wpuf-border-primary wpuf-p-1">
<path stroke-linecap="round" stroke-linejoin="round" d="M5 12h14" />
</svg>
</div>
<div
v-if="index === options.length - 1"
class="plus-buttons hover:wpuf-cursor-pointer !wpuf-border-0 wpuf-mt-1"
@click="add_option">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="wpuf-ml-1 wpuf-size-6 wpuf-border wpuf-rounded-2xl wpuf-border-gray-400 wpuf-p-1">
<path stroke-linecap="round" stroke-linejoin="round" d="M12 4.5v15m7.5-7.5h-15" />
</svg>
</div>
</td>
</tr>
</tbody>
</table>

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (1)
assets/js-templates/form-components.php (1)

1453-1462: 🛠️ Refactor suggestion

Enhance tooltip accessibility

The help text tooltip implementation should include proper ARIA attributes and keyboard interaction support.

 <span
     class="field-helper-text wpuf-ml-2"
     :data-placement="placement"
-    data-toggle="tooltip"
+    role="tooltip"
+    :aria-label="text"
+    tabindex="0"
+    @keydown.enter="toggleTooltip"
+    @keydown.space="toggleTooltip"
     data-container="body">
     <svg 
         xmlns="http://www.w3.org/2000/svg" 
         width="18" 
         height="18" 
         fill="none"
+        role="img"
+        aria-hidden="true"
     >
🧹 Nitpick comments (1)
assets/js-templates/form-components.php (1)

1430-1433: Consider enhancing the text editor component.

The current text editor implementation could be improved by:

  • Adding support for keyboard shortcuts
  • Implementing proper focus management
  • Adding a toolbar customization option
  • Supporting content formatting preservation

Would you like me to provide a more detailed implementation suggestion?

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 879ee1b and ceb6a49.

📒 Files selected for processing (3)
  • admin/form-builder/assets/js/components/field-radio/template.php (1 hunks)
  • admin/form-builder/assets/js/components/form-radio_field/template.php (1 hunks)
  • assets/js-templates/form-components.php (16 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • admin/form-builder/assets/js/components/form-radio_field/template.php
  • admin/form-builder/assets/js/components/field-radio/template.php
🔇 Additional comments (1)
assets/js-templates/form-components.php (1)

148-165: 🛠️ Refactor suggestion

Enhance accessibility of action buttons.

The action buttons lack proper ARIA labels and keyboard interaction support.

Add appropriate ARIA attributes and keyboard support:

 <span :class="action_button_classes">
     <i
-        class="fa fa-arrows move wpuf-pr-2 wpuf-rounded-l-md hover:!wpuf-cursor-move wpuf-border-r wpuf-border-green-200"></i>
+        class="fa fa-arrows move wpuf-pr-2 wpuf-rounded-l-md hover:!wpuf-cursor-move wpuf-border-r wpuf-border-green-200"
+        role="button"
+        tabindex="0"
+        aria-label="Move field"
+        @keydown.enter="handleMove"
+        @keydown.space="handleMove"></i>
 </span>
 <span
     :class="action_button_classes"
+    role="button"
+    tabindex="0"
     @click="open_field_settings(field.id)">
     <i
         class="fa fa-pencil"></i>
         Edit
 </span>

Likely invalid or redundant comment.

Comment on lines +89 to +90
<h2 class="wpuf-text-lg wpuf-text-gray-800"><?php esc_html_e( 'Add fields and build your desired form', 'wp-user-frontend' ); ?></h2>
<p class="wpuf-text-sm wpuf-text-gray-500"><?php esc_html_e( 'Add fields and build your desired form', 'wp-user-frontend' ); ?></p>
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Fix duplicate text in empty state message.

The same text is used for both the heading and paragraph, which is redundant:

<h2>Add fields and build your desired form</h2>
<p>Add fields and build your desired form</p>

Consider using different, complementary messages to better guide the user. For example:

-<p class="wpuf-text-sm wpuf-text-gray-500"><?php esc_html_e( 'Add fields and build your desired form', 'wp-user-frontend' ); ?></p>
+<p class="wpuf-text-sm wpuf-text-gray-500"><?php esc_html_e( 'Drag and drop fields from the right sidebar to start building your form', 'wp-user-frontend' ); ?></p>

Comment on lines +1288 to +1317
<div
v-if="field.inline !== 'yes'"
class="wpuf-space-y-2">
<div
v-if="has_options" v-for="(label, val) in field.options"
class="wpuf-flex wpuf-items-center">
<input
type="radio"
:class="builder_class_names('radio')">
<label
:value="val"
:checked="is_selected(val)">{{ label }}</label>
</div>
</div>

<span v-if="field.help" class="wpuf-help" v-html="field.help"/>
<div
v-else
class="wpuf-space-y-6 sm:wpuf-flex sm:wpuf-items-center sm:wpuf-space-x-10 sm:wpuf-space-y-0">
<div
v-if="has_options" v-for="(label, val) in field.options"
class="wpuf-flex wpuf-items-center">
<input type="radio" :class="builder_class_names('radio')">
<label
:value="val"
:checked="is_selected(val)"
class="wpuf-ml-3 wpuf-block wpuf-text-sm wpuf-font-medium wpuf-leading-6 wpuf-text-gray-900">{{ label }}</label>
</div>
</div>

<p v-if="field.help" class="wpuf-mt-2 wpuf-text-sm wpuf-text-gray-500" v-html="field.help"></p>
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Enhance radio field accessibility.

The radio field template needs proper ARIA attributes for better accessibility.

 <div class="wpuf-flex wpuf-items-center">
     <input
         type="radio"
+        :aria-label="label"
+        :aria-checked="is_selected(val)"
         :class="builder_class_names('radio')">
     <label
         :value="val"
+        :for="'radio-' + val"
         :checked="is_selected(val)"
         class="wpuf-ml-3 wpuf-block wpuf-text-sm wpuf-font-medium wpuf-leading-6 wpuf-text-gray-900">{{ label }}</label>
 </div>
📝 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
<div
v-if="field.inline !== 'yes'"
class="wpuf-space-y-2">
<div
v-if="has_options" v-for="(label, val) in field.options"
class="wpuf-flex wpuf-items-center">
<input
type="radio"
:class="builder_class_names('radio')">
<label
:value="val"
:checked="is_selected(val)">{{ label }}</label>
</div>
</div>
<span v-if="field.help" class="wpuf-help" v-html="field.help"/>
<div
v-else
class="wpuf-space-y-6 sm:wpuf-flex sm:wpuf-items-center sm:wpuf-space-x-10 sm:wpuf-space-y-0">
<div
v-if="has_options" v-for="(label, val) in field.options"
class="wpuf-flex wpuf-items-center">
<input type="radio" :class="builder_class_names('radio')">
<label
:value="val"
:checked="is_selected(val)"
class="wpuf-ml-3 wpuf-block wpuf-text-sm wpuf-font-medium wpuf-leading-6 wpuf-text-gray-900">{{ label }}</label>
</div>
</div>
<p v-if="field.help" class="wpuf-mt-2 wpuf-text-sm wpuf-text-gray-500" v-html="field.help"></p>
<div
v-if="field.inline !== 'yes'"
class="wpuf-space-y-2">
<div
v-if="has_options" v-for="(label, val) in field.options"
class="wpuf-flex wpuf-items-center">
<input
type="radio"
:aria-label="label"
:aria-checked="is_selected(val)"
:class="builder_class_names('radio')">
<label
:value="val"
:for="'radio-' + val"
:checked="is_selected(val)">{{ label }}</label>
</div>
</div>
<div
v-else
class="wpuf-space-y-6 sm:wpuf-flex sm:wpuf-items-center sm:wpuf-space-x-10 sm:wpuf-space-y-0">
<div
v-if="has_options" v-for="(label, val) in field.options"
class="wpuf-flex wpuf-items-center">
<input
type="radio"
:aria-label="label"
:aria-checked="is_selected(val)"
:class="builder_class_names('radio')">
<label
:value="val"
:for="'radio-' + val"
:checked="is_selected(val)"
class="wpuf-ml-3 wpuf-block wpuf-text-sm wpuf-font-medium wpuf-leading-6 wpuf-text-gray-900">{{ label }}</label>
</div>
</div>
<p v-if="field.help" class="wpuf-mt-2 wpuf-text-sm wpuf-text-gray-500" v-html="field.help"></p>

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
admin/form-builder/assets/js/mixins/global.js (1)

10-12: Consider improving type safety and documentation of the pro status check.

While the implementation is functional, there are a few improvements that could make it more robust:

  1. Consider using a boolean value instead of string comparison
  2. Add error handling for when wpuf_form_builder is undefined
  3. Add JSDoc documentation explaining the property's purpose

Here's a suggested improvement:

+/**
+ * Checks if the pro version is active
+ * @returns {boolean} True if pro version is active, false otherwise
+ */
 is_pro_active: function () {
-    return wpuf_form_builder.is_pro_active === '1';
+    return Boolean(wpuf_form_builder?.is_pro_active);
 },
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ceb6a49 and 78bcb6a.

📒 Files selected for processing (3)
  • admin/form-builder/assets/js/mixins/global.js (1 hunks)
  • admin/form-builder/views/form-builder-v4.1.php (1 hunks)
  • assets/js/wpuf-form-builder-mixins.js (6 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • admin/form-builder/views/form-builder-v4.1.php
🔇 Additional comments (7)
admin/form-builder/assets/js/mixins/global.js (1)

8-12: Verify integration with existing utility methods.

The new is_pro_active property might affect the behavior of form builder features. Please ensure that all utility methods in this mixin handle both pro and free variations correctly.

Let's verify the usage of this property across the codebase:

✅ Verification successful

Integration verified - implementation is consistent

The is_pro_active property is correctly integrated with existing utility methods across the codebase, consistently used for pro feature validation in field settings, and maintains uniform behavior in both pro and free variations.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for usage of is_pro_active in Vue templates and components
rg "is_pro_active" --type js

Length of output: 1462

assets/js/wpuf-form-builder-mixins.js (6)

52-56: LGTM! Well-structured pro feature check.

The method effectively determines if a template should be shown as a pro preview based on the pro version status and template settings.


60-62: LGTM! Clear and consistent button styling.

The computed property provides a consistent set of Tailwind CSS classes for action buttons.


74-74: Excellent fix for Vue.js props initialization!

Using arrow functions to return default objects is the correct way to prevent shared references between component instances. This change follows Vue.js best practices and prevents potential bugs caused by mutating shared state.

Also applies to: 317-317, 322-322


89-89: LGTM! Syntax fix.

Fixed the missing closing brace in the computed property.


101-131: Refactor class generation for better maintainability.

The current implementation could be improved by:

  1. Extracting CSS classes to a configuration object
  2. Adding input validation
  3. Removing duplicate classes

This matches the refactoring suggestion from a previous review.

+ const FIELD_CLASSES = {
+   base: 'wpuf-block wpuf-rounded-md wpuf-py-1.5 wpuf-text-gray-900 wpuf-shadow-sm',
+   common: 'placeholder:wpuf-text-gray-400 sm:wpuf-text-sm sm:wpuf-leading-6',
+   upload_btn: 'file-selector wpuf-rounded-md wpuf-btn-secondary',
+   radio: 'wpuf-ml-3 wpuf-block wpuf-text-sm wpuf-font-medium wpuf-leading-6 wpuf-text-gray-900',
+   checkbox: 'wpuf-h-4 wpuf-w-4 wpuf-rounded wpuf-border-gray-300 !wpuf-mt-0.5',
+   dropdown: 'wpuf-block wpuf-w-full wpuf-min-w-full'
+ };

  builder_class_names: function(type_class) {
+   if (!type_class || typeof type_class !== 'string') {
+     console.warn('Invalid type_class provided to builder_class_names');
+     return [];
+   }
    
    var commonClasses = '';
    
-   switch (type_class) {
-     case 'upload_btn':
-       commonClasses = 'file-selector  wpuf-rounded-md wpuf-btn-secondary';
-       break;
-     // ... other cases
+   commonClasses = FIELD_CLASSES[type_class] || FIELD_CLASSES.base;
+   commonClasses += ' ' + FIELD_CLASSES.common;

    return [
      type_class,
      this.required_class(),
      'wpuf_' + this.field.name + '_' + this.form_id,
      commonClasses
    ];
  },

161-163: LGTM! Clear pro version status check.

The computed property provides a clean way to check the pro version status throughout the application.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (5)
admin/form-builder/assets/js/components/form-column_field/index.js (2)

118-120: Consider using a more type-safe approach for class definitions.

The computed property correctly defines hover states using Tailwind CSS classes. However, consider using an array of classes for better maintainability and type safety.

-        action_button_classes: function() {
-            return 'hover:wpuf-cursor-pointer hover:wpuf-text-white';
+        action_button_classes: function() {
+            return [
+                'hover:wpuf-cursor-pointer',
+                'hover:wpuf-text-white'
+            ].join(' ');
+        },

122-131: Add input validation for columns count.

The computed property correctly generates column classes, but could benefit from input validation to handle edge cases.

         columnClasses: function() {
-            var columns_count = parseInt( this.field.columns );
+            var columns_count = Math.max(1, Math.min(3, parseInt(this.field.columns) || 1));
             var columns = [];
 
             for (var i = 1; i <= columns_count; i++) {
                 columns.push('column-' + i);
             }
 
             return columns;
         }
assets/js/wpuf-form-builder-components.js (3)

332-332: Simplify boolean expressions

The ternary operators returning boolean literals can be simplified.

- return (this.field_settings[template] && this.field_settings[template].pro_feature) ? true : false;
+ return !!(this.field_settings[template] && this.field_settings[template].pro_feature);

- return (field.recaptcha_type && 'invisible_recaptcha' === field.recaptcha_type) ? true : false;
+ return !!(field.recaptcha_type && 'invisible_recaptcha' === field.recaptcha_type);

Also applies to: 363-363

🧰 Tools
🪛 Biome (1.9.4)

[error] 332-332: Unnecessary use of boolean literals in conditional expression.

Simplify your code by directly assigning the result without using a ternary operator.
If your goal is negation, you may use the logical NOT (!) or double NOT (!!) operator for clearer and concise code.
Check for more details about NOT operator.
Unsafe fix: Remove the conditional expression with

(lint/complexity/noUselessTernary)


[error] 332-332: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


1557-1561: Consider adding loading state for pro status check

The component relies on a global wpuf_form_builder.is_pro_active check. Consider adding a loading state to handle cases where this check might be delayed.

 data: function () {
     return {
         searched_fields: '',
         is_pro_active: wpuf_form_builder.is_pro_active,
+        is_loading: true
     };
 },

1665-1705: Optimize search performance

The search implementation rebuilds the entire panel structure on every keystroke. Consider debouncing the search to improve performance.

+ import { debounce } from 'lodash';

 watch: {
-    searched_fields: function(searchValue) {
+    searched_fields: debounce(function(searchValue) {
         // ... existing code ...
-    }
+    }, 300)
 }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 78bcb6a and 1617bf1.

📒 Files selected for processing (2)
  • admin/form-builder/assets/js/components/form-column_field/index.js (4 hunks)
  • assets/js/wpuf-form-builder-components.js (15 hunks)
🧰 Additional context used
🪛 Biome (1.9.4)
assets/js/wpuf-form-builder-components.js

[error] 332-332: Unnecessary use of boolean literals in conditional expression.

Simplify your code by directly assigning the result without using a ternary operator.
If your goal is negation, you may use the logical NOT (!) or double NOT (!!) operator for clearer and concise code.
Check for more details about NOT operator.
Unsafe fix: Remove the conditional expression with

(lint/complexity/noUselessTernary)


[error] 332-332: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 355-355: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 363-363: Unnecessary use of boolean literals in conditional expression.

Simplify your code by directly assigning the result without using a ternary operator.
If your goal is negation, you may use the logical NOT (!) or double NOT (!!) operator for clearer and concise code.
Check for more details about NOT operator.
Unsafe fix: Remove the conditional expression with

(lint/complexity/noUselessTernary)


[error] 301-301: This aliasing of this is unnecessary.

Arrow functions inherits this from their enclosing scope.
Safe fix: Use this instead of an alias.

(lint/complexity/noUselessThisAlias)


[error] 1631-1631: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

🔇 Additional comments (6)
admin/form-builder/assets/js/components/form-column_field/index.js (3)

5-6: LGTM! Mixins are properly declared.

The mixins are correctly ordered and follow Vue.js best practices.


139-139: LGTM! Pro feature validation is properly implemented.

The pro feature check is correctly placed within the template availability validation, following good separation of concerns.


30-30: Verify DOM structure matches new selectors.

The selectors have been updated:

  • Changed from .wpuf-column-field-inner-columns to .wpuf-field-columns
  • Button removal now uses .wpuf-field-button

Please ensure these changes align with the template structure in #tmpl-wpuf-form-column_field.

Also applies to: 63-63

✅ Verification successful

Selector changes are correctly aligned with template structure

The updated selectors match the DOM structure in assets/js-templates/form-components.php:

  • .wpuf-field-columns is the parent container with nested .wpuf-column-inner-fields
  • .wpuf-field-button is correctly used for field buttons
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for template structure to verify selector changes
rg -l "tmpl-wpuf-form-column_field" | xargs rg -A 5 "wpuf-field-columns|wpuf-field-button"

Length of output: 5325

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

41-41: Selector change improves drag handle specificity

The change to use .field-buttons .move as the handle selector provides better specificity and follows a more maintainable pattern.


777-782: 🛠️ Refactor suggestion

Enhance accessibility for custom dropdown implementation

The custom dropdown implementation should include ARIA attributes and keyboard navigation support for better accessibility.

 data: function () {
     return {
         showOptions: false,
         selectedOption: 'Select an option',
+        // Add aria attributes
+        ariaExpanded: false,
+        activeDescendant: null
     };
 },

Likely invalid or redundant comment.


300-319: 🛠️ Refactor suggestion

Remove unnecessary this aliasing

The use of var self = this is unnecessary when using arrow functions as they inherit the lexical scope.

 delete_field: function(index) {
-    var self = this;
     (Swal.fire({
-        text: self.i18n.delete_field_warn_msg,
+        text: this.i18n.delete_field_warn_msg,
         icon: 'warning',
         showCancelButton: true,
         confirmButtonColor: '#d54e21',
-        confirmButtonText: self.i18n.yes_delete_it,
-        cancelButtonText: self.i18n.no_cancel_it,
+        confirmButtonText: this.i18n.yes_delete_it,
+        cancelButtonText: this.i18n.no_cancel_it,
         customClass: {
             confirmButton: 'btn btn-success',
             cancelButton: 'btn btn-danger',
         }
     })).then((result) => {
         if (result.isConfirmed) {
-            self.$store.commit('delete_form_field_element', index);
+            this.$store.commit('delete_form_field_element', index);
         }
     });

Likely invalid or redundant comment.

🧰 Tools
🪛 Biome (1.9.4)

[error] 301-301: This aliasing of this is unnecessary.

Arrow functions inherits this from their enclosing scope.
Safe fix: Use this instead of an alias.

(lint/complexity/noUselessThisAlias)

Comment on lines +188 to +189
Vue.component('builder-stage-v4-1', {
template: '#tmpl-wpuf-builder-stage-v4-1',
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consider extracting common logic between builder stages

The new builder-stage-v4-1 component largely duplicates code from the original builder-stage component. Consider extracting shared functionality into a mixin or base component to improve maintainability.

+ const builderStageMixin = {
+   computed: {
+     form_fields() { ... },
+     field_settings() { ... },
+     hidden_fields() { ... },
+     editing_form_id() { ... },
+     pro_link() { ... }
+   },
+   methods: {
+     open_field_settings() { ... },
+     clone_field() { ... },
+     delete_field() { ... }
+   }
+ };

 Vue.component('builder-stage-v4-1', {
   template: '#tmpl-wpuf-builder-stage-v4-1',
-  // Duplicate code
+  mixins: [builderStageMixin],
   // Component-specific code
 });

Also applies to: 191-192

Comment on lines +2064 to +2067
$( this.$el ).tooltip({
title: this.text,
placement: 'auto top'
});
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Improve tooltip initialization

The tooltip initialization should handle cleanup on component destroy to prevent memory leaks.

 mounted: function () {
     $(this.$el).tooltip({
         title: this.text,
         placement: 'auto top'
     });
 },
+ beforeDestroy: function() {
+     $(this.$el).tooltip('dispose');
+ }
📝 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
$( this.$el ).tooltip({
title: this.text,
placement: 'auto top'
});
$( this.$el ).tooltip({
title: this.text,
placement: 'auto top'
});
beforeDestroy: function() {
$(this.$el).tooltip('dispose');
}

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (3)
src/css/admin/form-builder.css (3)

6-12: Consider enhancing button accessibility and states.

The button styles could benefit from additional accessibility and state improvements:

 .wpuf-btn-primary {
-    @apply wpuf-rounded-md wpuf-bg-green-800 wpuf-text-white wpuf-px-3.5 wpuf-py-2 wpuf-text-sm wpuf-font-semibold hover:wpuf-bg-green-700 hover:wpuf-text-white focus:wpuf-text-white focus:wpuf-shadow-none;
+    @apply wpuf-rounded-md wpuf-bg-green-800 wpuf-text-white wpuf-px-3.5 wpuf-py-2 wpuf-text-sm wpuf-font-semibold 
+           hover:wpuf-bg-green-700 hover:wpuf-text-white 
+           focus:wpuf-text-white focus:wpuf-shadow-none focus:wpuf-outline-none focus:wpuf-ring-2 focus:wpuf-ring-green-500 focus:wpuf-ring-offset-2
+           disabled:wpuf-opacity-50 disabled:wpuf-cursor-not-allowed;
 }

 .wpuf-btn-secondary {
-    @apply wpuf-rounded-md wpuf-bg-green-50 wpuf-text-green-700 wpuf-px-3.5 wpuf-py-2 wpuf-text-sm wpuf-border wpuf-border-green-300 wpuf-font-semibold hover:wpuf-bg-green-100 hover:wpuf-text-white;
+    @apply wpuf-rounded-md wpuf-bg-green-50 wpuf-text-green-700 wpuf-px-3.5 wpuf-py-2 wpuf-text-sm wpuf-border wpuf-border-green-300 wpuf-font-semibold 
+           hover:wpuf-bg-green-100 hover:wpuf-text-green-800
+           focus:wpuf-outline-none focus:wpuf-ring-2 focus:wpuf-ring-green-500 focus:wpuf-ring-offset-2
+           disabled:wpuf-opacity-50 disabled:wpuf-cursor-not-allowed;
 }

31-47: Consider using Tailwind's built-in transition utilities.

Instead of creating custom utilities, you could use Tailwind's built-in transition utilities like transition-all, duration-100, and ease-out. This would reduce code duplication and maintain consistency with Tailwind's utility-first approach.


65-68: Avoid using !important declarations.

Using !important is generally discouraged as it makes styles harder to override and maintain. Consider increasing selector specificity or restructuring the CSS.

 .selectize-control.multi .selectize-input [data-value] {
-    background: #16a34a !important;
-    border: 1px solid transparent !important;
+    background: #16a34a;
+    border: 1px solid transparent;
 }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1617bf1 and 9090d49.

📒 Files selected for processing (1)
  • src/css/admin/form-builder.css (1 hunks)
🧰 Additional context used
🪛 Biome (1.9.4)
src/css/admin/form-builder.css

[error] 93-93: expected } but instead the file ends

the file ends here

(parse)


[error] 62-62: Unexpected shorthand property background after background-color

(lint/suspicious/noShorthandPropertyOverrides)

🔇 Additional comments (3)
src/css/admin/form-builder.css (3)

1-3: LGTM! Tailwind directives are properly imported.


49-56: LGTM! Smooth transition implementation for dropdown items.


70-93: ⚠️ Potential issue

Simplify form field width styles and fix syntax.

  1. The width styles are duplicated with and without the body selector. Consider consolidating them.
  2. The file is missing a closing brace.
-ul.wpuf-form li.field-size-small .wpuf-fields {
-    width: 30%;
-}
-
-ul.wpuf-form li.field-size-medium .wpuf-fields {
-    width: 50%;
-}
-
 #wpuf-form-builder .wpuf-fields {
     float: none;
     width: auto;
 }
+
 body ul.wpuf-form li.field-size-large .wpuf-fields {
     width: 100% !important;
 }
+
 body ul.wpuf-form li.field-size-medium .wpuf-fields {
     width: 50% !important;
 }
+
 body ul.wpuf-form li.field-size-small .wpuf-fields {
     width: 30% !important;
 }
+
 body ul.wpuf-form li .wpuf-fields {
     width: 70% !important;
-}
+}}

Likely invalid or redundant comment.

🧰 Tools
🪛 Biome (1.9.4)

[error] 93-93: expected } but instead the file ends

the file ends here

(parse)

Comment on lines +58 to +63
.wpuf-pattern-1 {
border: 1px dashed #ddd;
background-color: #ffffff;
opacity: 1;
background: repeating-linear-gradient( -45deg, #dcfce7, #dcfce7 2px, #ffffff 2px, #ffffff 6px );
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Fix background property override.

The background-color property is being overridden by the background shorthand property. Combine them or remove the redundant property.

 .wpuf-pattern-1 {
     border: 1px dashed #ddd;
-    background-color: #ffffff;
-    opacity: 1;
-    background: repeating-linear-gradient( -45deg, #dcfce7, #dcfce7 2px, #ffffff 2px, #ffffff 6px );
+    background: #ffffff repeating-linear-gradient( -45deg, #dcfce7, #dcfce7 2px, #ffffff 2px, #ffffff 6px );
+    opacity: 1;
 }
📝 Committable suggestion

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

Suggested change
.wpuf-pattern-1 {
border: 1px dashed #ddd;
background-color: #ffffff;
opacity: 1;
background: repeating-linear-gradient( -45deg, #dcfce7, #dcfce7 2px, #ffffff 2px, #ffffff 6px );
}
.wpuf-pattern-1 {
border: 1px dashed #ddd;
background: #ffffff repeating-linear-gradient( -45deg, #dcfce7, #dcfce7 2px, #ffffff 2px, #ffffff 6px );
opacity: 1;
}
🧰 Tools
🪛 Biome (1.9.4)

[error] 62-62: Unexpected shorthand property background after background-color

(lint/suspicious/noShorthandPropertyOverrides)

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

Successfully merging this pull request may close these issues.

1 participant