Skip to content

Conversation

@sapayth
Copy link
Member

@sapayth sapayth commented Oct 29, 2025

closes #1027, fix #1257

Summary

This PR introduces N8N workflow automation integration for post forms, allowing form submissions to automatically trigger N8N webhooks. The integration supports multiple authentication methods (Basic Auth, Header Auth, and JWT) and sends comprehensive post data including custom fields to configured N8N webhooks. Additionally, this PR includes significant enhancements including an AI Form Builder feature, subscription pack design improvements, and various bug fixes and UI refinements.

Testing Recommendations

N8N Integration:

  • Test webhook triggering with different authentication methods
  • Verify data payload includes all expected fields
  • Test with various post types and custom fields
  • Verify error handling when webhook URL is invalid

Summary by CodeRabbit

  • New Features

    • N8N webhook integration for form submissions with multiple auth modes and per-form enable toggle.
    • Password-preview field type with masked display.
  • New/Improved Features

    • Field dependency system upgraded: supports multiple/JSON rules and real-time evaluation.
  • Style

    • Removed vendor-prefixed backdrop-filter; added backdrop blur and new emerald background + focus variant; adjusted pro-icon alignment.
  • Chores

    • Updated translations to include N8N-related strings.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Oct 29, 2025

Walkthrough

Adds an N8N integration and loader, extends Settings API to emit and sanitize multi-field dependency attributes and adds comprehensive front-end dependency logic, introduces a password-preview field renderer (duplicated), removes vendor-prefixed backdrop-filter CSS usage, and updates POT translations with N8N strings.

Changes

Cohort / File(s) Summary
N8N integration
includes/Integrations.php, includes/Integrations/WPUF_N8N_Integration.php
Adds a new WPUF_N8N_Integration class plus an unconditional loader path in Integrations.php; implements webhook dispatch on post insert with auth modes (none, basic_auth, header_auth, jwt_auth), optional JWT creation, global and per-form settings UI, and error logging.
Settings API & frontend deps
Lib/WeDevs_Settings_API.php
Adds depends_on_value to field args; outputs data-depends-on / data-depends-on-value for text/select fields; expands wp_kses allowed attributes; updates JS to support single/multi/JSON dependencies, robust selectors, event bindings, and centralized dependency evaluation.
Password preview renderer (duplicate)
wpuf-functions.php
Adds wpuf_settings_password_preview($args) to render a masked password input that emits dependency data attributes and pro-preview HTML — the function is declared twice (duplicate definitions present).
Form-builder settings JS
admin/form-builder/assets/js/form-builder.js
Adds n8n_webhook_url dependent field under settings dependencies to show when enable_n8n is true.
CSS: backdrop-filter cleanup & utilities
assets/css/admin/form-builder.css, assets/css/ai-form-builder.css, assets/css/admin.css
Removes -webkit-backdrop-filter vendor-prefixed entries from transition-property lists, retains standard backdrop-filter, adds .wpuf-backdrop-blur-sm and .wpuf-bg-emerald-50/50 utilities, and tweaks pro-icon alignment styling.
Translations (POT)
languages/wp-user-frontend.pot
Updates POT timestamp and source references; adds N8N-related translation strings (labels, auth options, webhook URL, descriptors).

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • New integration class with networking/auth: review WPUF_N8N_Integration::send_post_to_n8n() for input validation, error handling, and wp_remote_post usage.
  • JWT creation: audit create_jwt_token() for correct HS256 implementation, claim selection, expiry handling, and secret usage.
  • Duplicate function: consolidate the duplicated wpuf_settings_password_preview() declarations in wpuf-functions.php.
  • Settings API JS: verify selector strategies, performance with many fields, and correctness for array/JSON dependency cases.
  • Sanitization: confirm added data-depends-on / data-depends-on-value entries are safely escaped and allowed in wp_kses.

Possibly related PRs

  • #1495 — Expands conditional dependency support in the Settings API; strongly related to multi-field dependency attributes and JS handling.
  • #1734 — Changes to pro-preview/pro-icon rendering and admin CSS; related to pro-preview output and CSS adjustments.

Suggested labels

needs: dev review

Poem

🐰 I hopped through settings, twitching my nose,

Webhooks and secrets in tidy new rows.
Dependencies listen when fields say hello,
CSS trimmed its whiskers for a cleaner glow.
A masked little password — blink, then go!

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning The PR includes multiple out-of-scope changes: CSS vendor-prefix removals (form-builder.css, ai-form-builder.css), password preview function, and pro-icon styling unrelated to the N8N integration objectives. Separate CSS refactoring, password preview utility, and styling changes into independent PRs; keep this PR focused solely on N8N integration and required POT file updates.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main feature added: N8N integration for post forms, which is the primary focus of the changeset.
Linked Issues check ✅ Passed The PR addresses issue #1257 by updating the POT file with N8N-related translation entries (confirmed in languages/wp-user-frontend.pot summary), and includes the N8N integration closure of #1027.
Docstring Coverage ✅ Passed Docstring coverage is 85.71% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

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: 8

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

1250-1256: n8n_webhook_url: use URL semantics and basic validation

  • Prefer type 'url' and a simple pattern/placeholder to reduce bad inputs (e.g., https://your-n8n-host/webhook/...).
  • Confirm the controlling field id 'enable_n8n' matches the actual DOM id used by FormDependencyHandler.
Lib/WeDevs_Settings_API.php (1)

144-145: Good addition of depends_on_value + safe rendering; prefer wp_json_encode

  • The new depends_on_value plumbs through correctly and data attributes are allowed in wp_kses. LGTM.
  • Minor: use wp_json_encode instead of json_encode for better encoding and consistency in WP.

Also applies to: 177-205, 324-353

includes/Integrations.php (1)

31-38: Simplify error logging.

The print_r() call on Line 37 is redundant since the argument is already a string concatenation. This can be simplified for clarity.

Apply this diff:

-                    \WP_User_Frontend::log( 'integration', print_r( $external_class . ' integration failed', true ) );
+                    \WP_User_Frontend::log( 'integration', $external_class . ' integration failed' );
includes/Integrations/WPUF_N8N_Integration.php (1)

105-139: Consider extracting authentication logic.

The authentication switch statement is comprehensive but could benefit from extraction into separate private methods for better maintainability and testability.

Consider refactoring like this:

switch ( $auth_type ) {
    case 'basic_auth':
        $this->add_basic_auth_header( $headers, $n8n_settings );
        break;
    case 'header_auth':
        $this->add_header_auth( $headers, $n8n_settings );
        break;
    case 'jwt_auth':
        $this->add_jwt_auth_header( $headers, $n8n_settings );
        break;
}

Note: The PHPCS warnings about base64_encode() on Lines 110, 367, 368, and 371 are false positives. The function is legitimately used for Basic Authentication and JWT token encoding, not code obfuscation.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f1ba22d and 79d483e.

📒 Files selected for processing (5)
  • Lib/WeDevs_Settings_API.php (5 hunks)
  • assets/js/wpuf-form-builder.js (1 hunks)
  • includes/Integrations.php (1 hunks)
  • includes/Integrations/WPUF_N8N_Integration.php (1 hunks)
  • wpuf-functions.php (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (4)
Lib/WeDevs_Settings_API.php (1)
wpuf-functions.php (1)
  • wpuf_get_pro_preview_html (4696-4702)
wpuf-functions.php (1)
Lib/WeDevs_Settings_API.php (3)
  • WeDevs_Settings_API (13-892)
  • get_option (579-588)
  • get_field_description (162-170)
includes/Integrations.php (2)
includes/Integrations/WPUF_N8N_Integration.php (1)
  • __construct (17-25)
wpuf.php (2)
  • __construct (74-88)
  • log (323-326)
includes/Integrations/WPUF_N8N_Integration.php (2)
includes/Integrations.php (2)
  • Integrations (10-66)
  • __construct (29-48)
wpuf-functions.php (1)
  • wpuf_is_checkbox_or_toggle_on (5643-5645)
🪛 GitHub Check: Run PHPCS inspection
includes/Integrations/WPUF_N8N_Integration.php

[warning] 371-371:
base64_encode() can be used to obfuscate code which is strongly discouraged. Please verify that the function is used for benign reasons.


[warning] 368-368:
base64_encode() can be used to obfuscate code which is strongly discouraged. Please verify that the function is used for benign reasons.


[warning] 367-367:
base64_encode() can be used to obfuscate code which is strongly discouraged. Please verify that the function is used for benign reasons.


[failure] 367-367:
Expected 1 space after the array opener in a single line array. Found: no spaces


[failure] 365-365:
Closing parenthesis of a multi-line function call must be on a line by itself


[failure] 361-361:
Opening parenthesis of a multi-line function call must be the last content on the line


[warning] 361-361:
json_encode() is discouraged. Use wp_json_encode() instead.


[failure] 359-359:
Closing parenthesis of a multi-line function call must be on a line by itself


[failure] 358-358:
There should be a comma after the last array item in a multi-line array.


[failure] 356-356:
Opening parenthesis of a multi-line function call must be the last content on the line


[warning] 356-356:
json_encode() is discouraged. Use wp_json_encode() instead.


[failure] 272-272:
There should be a comma after the last array item in a multi-line array.


[failure] 239-239:
Multi-line function call not indented correctly; expected 24 spaces but found 28


[warning] 110-110:
base64_encode() can be used to obfuscate code which is strongly discouraged. Please verify that the function is used for benign reasons.


[failure] 91-91:
Array keys must be surrounded by spaces unless they contain a string or an integer.


[failure] 88-88:
The shorthand list syntax "[]" to destructure arrays is not available in PHP 7.0 or earlier.

🪛 PHPMD (2.15.0)
includes/Integrations/WPUF_N8N_Integration.php

88-88: Avoid unused local variables such as '$multi_repeated'. (undefined)

(UnusedLocalVariable)


88-88: Avoid unused local variables such as '$files'. (undefined)

(UnusedLocalVariable)


142-142: Avoid unused local variables such as '$response'. (undefined)

(UnusedLocalVariable)

🔇 Additional comments (8)
wpuf-functions.php (1)

4041-4085: No duplicate function declarations detected—verification confirms safe declaration.

Ripgrep search found only one definition of wpuf_settings_password_preview at line 4047 in wpuf-functions.php. No fatal redeclaration issues exist.

includes/Integrations.php (2)

26-26: LGTM! N8N integration entry added.

The integration registry entry is correctly formatted and consistent with existing integrations.


39-39: LGTM! Correct use of elseif.

The change from if to elseif correctly prevents the N8N integration from being processed twice.

includes/Integrations/WPUF_N8N_Integration.php (5)

17-25: LGTM! Constructor properly registers hooks.

The constructor correctly registers filters for settings UI and an action hook for post submission with appropriate priority.


39-58: LGTM! Proper validation and sanitization.

The method correctly validates that N8N is enabled, the webhook URL exists, and the post is valid before proceeding. The use of esc_url_raw() for URL sanitization is appropriate.


161-169: LGTM! Settings section added correctly.

The method properly adds the N8N settings section to the configuration.


305-317: LGTM! Menu title with icon added correctly.

The method properly adds N8N to the form builder menu with a custom SVG icon.


328-344: LGTM! Form settings configured correctly.

The method properly adds form-level N8N configuration options. The webhook URL field will be conditionally displayed based on the enable_n8n toggle, as configured in the JavaScript dependencies.

Comment on lines +88 to +92
[ $meta_key_value, $multi_repeated, $files ] = self::prepare_meta_fields( $meta_vars );

foreach ( $meta_key_value as $meta_key => $meta_value ) {
$post_data[$meta_key] = $meta_value;
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Address unused variables and potential PHP compatibility issue.

Line 88 has two concerns:

  1. Array destructuring syntax [ $meta_key_value, $multi_repeated, $files ] requires PHP 7.1+, which may cause compatibility issues if the plugin supports PHP 7.0.
  2. Variables $multi_repeated and $files are destructured but never used.

Consider one of these solutions:

Solution 1: Only destructure what's needed

-            [ $meta_key_value, $multi_repeated, $files ] = self::prepare_meta_fields( $meta_vars );
+            [ $meta_key_value ] = self::prepare_meta_fields( $meta_vars );

Solution 2: Use traditional assignment if PHP 7.0 support is required

-            [ $meta_key_value, $multi_repeated, $files ] = self::prepare_meta_fields( $meta_vars );
+            $prepared = self::prepare_meta_fields( $meta_vars );
+            $meta_key_value = $prepared[0];

Please verify the minimum PHP version requirement for this plugin to determine the appropriate solution.


🏁 Script executed:

#!/bin/bash
# Find PHP version requirement in composer.json or other config files
echo "=== Checking PHP version requirement ==="
if [ -f "composer.json" ]; then
  echo "From composer.json:"
  jq -r '.require.php // "Not specified"' composer.json
fi

if [ -f "readme.txt" ]; then
  echo "From readme.txt (PHP requirement lines):"
  grep -i "php" readme.txt | head -5
fi

if [ -f "package.json" ]; then
  echo "From package.json:"
  jq -r '.engines.php // "Not specified"' package.json 2>/dev/null || echo "N/A"
fi

Length of output: 409


🏁 Script executed:

#!/bin/bash
# Examine the specific file and lines in question
echo "=== Examining WPUF_N8N_Integration.php around lines 88-92 ==="
if [ -f "includes/Integrations/WPUF_N8N_Integration.php" ]; then
  echo "Lines 80-100:"
  sed -n '80,100p' "includes/Integrations/WPUF_N8N_Integration.php"
else
  echo "File not found at includes/Integrations/WPUF_N8N_Integration.php"
  find . -name "WPUF_N8N_Integration.php" -type f 2>/dev/null
fi

Length of output: 837


🏁 Script executed:

#!/bin/bash
# Search for usage of $multi_repeated and $files variables in the file
echo "=== Searching for $multi_repeated usage ==="
rg -n '\$multi_repeated' "includes/Integrations/" -C 3 || echo "No matches for \$multi_repeated"

echo ""
echo "=== Searching for $files usage (excluding function parameter context) ==="
rg -n '\$files' "includes/Integrations/" -C 3 || echo "No matches for \$files"

Length of output: 1395


🏁 Script executed:

#!/bin/bash
# Find the prepare_meta_fields method to understand return structure
echo "=== Searching for prepare_meta_fields method definition ==="
rg -n 'prepare_meta_fields' "includes/Integrations/" -A 15 -B 2 | head -50

Length of output: 1653


🏁 Script executed:

#!/bin/bash
# Search for prepare_meta_fields method definition more broadly (may be in parent class or trait)
echo "=== Searching for prepare_meta_fields method definition anywhere ==="
rg -n 'function prepare_meta_fields|public.*prepare_meta_fields|private.*prepare_meta_fields' -A 20 || echo "No explicit function definition found"

echo ""
echo "=== Checking for class definition and inheritance in WPUF_N8N_Integration.php ==="
head -50 "includes/Integrations/WPUF_N8N_Integration.php"

Length of output: 7965


Fix PHP 7.1+ incompatibility and remove unused variables in line 88.

This file uses FieldableTrait which contains prepare_meta_fields(). The plugin supports PHP 5.6+ (per readme.txt and composer.json), but line 88 uses array destructuring syntax [ ... ] which requires PHP 7.1+. This is a breaking change. Additionally, $multi_repeated and $files are destructured but never used.

Use only what's needed:

-            [ $meta_key_value, $multi_repeated, $files ] = self::prepare_meta_fields( $meta_vars );
+            [ $meta_key_value ] = self::prepare_meta_fields( $meta_vars );

Or for PHP 5.6 compatibility:

-            [ $meta_key_value, $multi_repeated, $files ] = self::prepare_meta_fields( $meta_vars );
+            $prepared = self::prepare_meta_fields( $meta_vars );
+            $meta_key_value = $prepared[0];
📝 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
[ $meta_key_value, $multi_repeated, $files ] = self::prepare_meta_fields( $meta_vars );
foreach ( $meta_key_value as $meta_key => $meta_value ) {
$post_data[$meta_key] = $meta_value;
}
$prepared = self::prepare_meta_fields( $meta_vars );
$meta_key_value = $prepared[0];
foreach ( $meta_key_value as $meta_key => $meta_value ) {
$post_data[$meta_key] = $meta_value;
}
🧰 Tools
🪛 GitHub Check: Run PHPCS inspection

[failure] 91-91:
Array keys must be surrounded by spaces unless they contain a string or an integer.


[failure] 88-88:
The shorthand list syntax "[]" to destructure arrays is not available in PHP 7.0 or earlier.

🪛 PHPMD (2.15.0)

88-88: Avoid unused local variables such as '$multi_repeated'. (undefined)

(UnusedLocalVariable)


88-88: Avoid unused local variables such as '$files'. (undefined)

(UnusedLocalVariable)

🤖 Prompt for AI Agents
In includes/Integrations/WPUF_N8N_Integration.php around lines 88 to 92, the
code uses PHP 7.1 array destructuring and binds unused variables; replace the
destructuring with PHP 5.6-compatible handling by calling
self::prepare_meta_fields($meta_vars) into a single variable and then extract
only the first element (the $meta_key_value) for use, dropping $multi_repeated
and $files; update the subsequent loop to use that extracted $meta_key_value.

Comment on lines +142 to +150
$response = wp_remote_post(
$n8n_webhook_url, [
'method' => 'POST',
'timeout' => 30,
'headers' => $headers,
'body' => wp_json_encode( $post_data ),
]
);
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Critical: Add error handling and response validation.

The webhook request response is captured but never checked for errors. Failed webhook deliveries will fail silently, making it impossible for users to debug integration issues.

Add error handling and logging:

             // Send data to N8N webhook
             $response = wp_remote_post(
                 $n8n_webhook_url, [
                     'method'  => 'POST',
                     'timeout' => 30,
                     'headers' => $headers,
                     'body'    => wp_json_encode( $post_data ),
                 ]
             );
+
+            // Check for errors
+            if ( is_wp_error( $response ) ) {
+                \WP_User_Frontend::log( 'n8n', 'Webhook delivery failed: ' . $response->get_error_message() );
+                return;
+            }
+
+            $response_code = wp_remote_retrieve_response_code( $response );
+            if ( $response_code < 200 || $response_code >= 300 ) {
+                $response_body = wp_remote_retrieve_body( $response );
+                \WP_User_Frontend::log( 'n8n', sprintf( 'Webhook returned %d: %s', $response_code, $response_body ) );
+            }
         }
🧰 Tools
🪛 PHPMD (2.15.0)

142-142: Avoid unused local variables such as '$response'. (undefined)

(UnusedLocalVariable)

🤖 Prompt for AI Agents
In includes/Integrations/WPUF_N8N_Integration.php around lines 142 to 150, the
wp_remote_post response is not validated or error-checked; update the code to
check for WP_Error (is_wp_error), verify HTTP status is 2xx, parse/validate the
response body (json_decode and check for expected keys), and log failures.
Specifically: after wp_remote_post, if is_wp_error($response) log the error
message and return/handle accordingly; otherwise get the status with
wp_remote_retrieve_response_code and if it's not between 200 and 299 log the
status, response body and headers; attempt to json_decode the body and validate
expected fields, logging malformed JSON; use a consistent logger (error_log or
WordPress logger) and include contextual info (webhook URL, payload id/user) in
logs to aid debugging.

Comment on lines +180 to +293
public function add_n8n_settings_fields( $fields ) {
$settings = [
'n8n' => [
[
'name' => 'authentication_type',
'label' => __( 'Authentication Type', 'wp-user-frontend' ),
'desc' => __(
'Select the authentication type for the N8N integration.',
'wp-user-frontend'
),
'type' => 'select',
'default' => 'none',
'options' => [
'none' => __( 'None', 'wp-user-frontend' ),
'basic_auth' => __( 'Basic Auth', 'wp-user-frontend' ),
'header_auth' => __( 'Header Auth', 'wp-user-frontend' ),
'jwt_auth' => __( 'JWT Auth', 'wp-user-frontend' ),
],
],
[
'name' => 'basic_auth_username',
'label' => __( 'Basic Auth Username', 'wp-user-frontend' ),
'desc' => __(
'Enter the username for the Basic Auth authentication.',
'wp-user-frontend'
),
'type' => 'text',
'depends_on' => 'authentication_type',
'depends_on_value' => 'basic_auth',
],
[
'name' => 'basic_auth_password',
'label' => __( 'Basic Auth Password', 'wp-user-frontend' ),
'desc' => __(
'Enter the password for the Basic Auth authentication.',
'wp-user-frontend'
),
'type' => 'text',
'callback' => 'wpuf_settings_password_preview',
'depends_on' => 'authentication_type',
'depends_on_value' => 'basic_auth',
],
[
'name' => 'header_auth_name',
'label' => __( 'Name', 'wp-user-frontend' ),
'desc' => __(
'Enter the name for the Header Auth authentication.',
'wp-user-frontend'
),
'type' => 'text',
'depends_on' => 'authentication_type',
'depends_on_value' => 'header_auth',
],
[
'name' => 'header_auth_value',
'label' => __( 'Header Auth Value', 'wp-user-frontend' ),
'desc' => __(
'Enter the value for the Header Auth authentication.',
'wp-user-frontend'
),
'type' => 'text',
'callback' => 'wpuf_settings_password_preview',
'depends_on' => 'authentication_type',
'depends_on_value' => 'header_auth',
],
[
'name' => 'jwt_key_type',
'label' => __( 'JWT Key Type', 'wp-user-frontend' ),
'desc' => __(
'Select the type of JWT key for the JWT Auth authentication.',
'wp-user-frontend'
),
'type' => 'select',
'default' => 'passphrase',
'options' => [
'passphrase' => __( 'Passphrase', 'wp-user-frontend' ),
'pem_key' => __( 'PEM Key', 'wp-user-frontend' ),
],
'depends_on' => 'authentication_type',
'depends_on_value' => 'jwt_auth',
],
[
'name' => 'jwt_key_passphrase',
'label' => __( 'Passphrase', 'wp-user-frontend' ),
'desc' => __(
'Enter the passphrase for the JWT Auth authentication.',
'wp-user-frontend'
),
'type' => 'text',
'callback' => 'wpuf_settings_password_preview',
'depends_on' => [
'authentication_type' => 'jwt_auth',
'jwt_key_type' => 'passphrase'
],
],
[
'name' => 'jwt_key_pem_key',
'label' => __( 'PEM Key', 'wp-user-frontend' ),
'desc' => __(
'Enter the PEM key for the JWT Auth authentication.',
'wp-user-frontend'
),
'type' => 'text',
'callback' => 'wpuf_settings_password_preview',
'depends_on' => [
'authentication_type' => 'jwt_auth',
'jwt_key_type' => 'pem_key',
],
],
],
];

return array_merge( $fields, $settings );
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Consider encrypting sensitive authentication credentials.

Authentication credentials (passwords, JWT secrets, API keys) are currently stored in plain text in the wp_options table. This poses a security risk if the database is compromised.

Consider implementing encryption for sensitive fields:

  1. Use WordPress's built-in encryption functions or a library like sodium (available in PHP 7.2+)
  2. Encrypt values before storing with update_option()
  3. Decrypt when retrieving with get_option()

Alternatively, document this security consideration and recommend that users:

  • Store N8N webhooks on a secure network
  • Use webhook URL query parameters for authentication instead of storing credentials
  • Regularly rotate credentials
🧰 Tools
🪛 GitHub Check: Run PHPCS inspection

[failure] 272-272:
There should be a comma after the last array item in a multi-line array.


[failure] 239-239:
Multi-line function call not indented correctly; expected 24 spaces but found 28


⚠️ Potential issue | 🟡 Minor

Fix coding standards violations.

The PHPCS static analysis identified formatting issues that should be corrected for consistency with WordPress coding standards.

Apply these fixes:

                         'desc'     => __(
                             'Enter the value for the Header Auth authentication.',
-                            'wp-user-frontend'
-                            ),
+                            'wp-user-frontend'
+                        ),
                         'depends_on' => [
                             'authentication_type' => 'jwt_auth',
-                            'jwt_key_type' => 'passphrase'
+                            'jwt_key_type' => 'passphrase',
                         ],
                         'depends_on' => [
                             'authentication_type' => 'jwt_auth',
                             'jwt_key_type'        => 'pem_key',
                         ],
📝 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
public function add_n8n_settings_fields( $fields ) {
$settings = [
'n8n' => [
[
'name' => 'authentication_type',
'label' => __( 'Authentication Type', 'wp-user-frontend' ),
'desc' => __(
'Select the authentication type for the N8N integration.',
'wp-user-frontend'
),
'type' => 'select',
'default' => 'none',
'options' => [
'none' => __( 'None', 'wp-user-frontend' ),
'basic_auth' => __( 'Basic Auth', 'wp-user-frontend' ),
'header_auth' => __( 'Header Auth', 'wp-user-frontend' ),
'jwt_auth' => __( 'JWT Auth', 'wp-user-frontend' ),
],
],
[
'name' => 'basic_auth_username',
'label' => __( 'Basic Auth Username', 'wp-user-frontend' ),
'desc' => __(
'Enter the username for the Basic Auth authentication.',
'wp-user-frontend'
),
'type' => 'text',
'depends_on' => 'authentication_type',
'depends_on_value' => 'basic_auth',
],
[
'name' => 'basic_auth_password',
'label' => __( 'Basic Auth Password', 'wp-user-frontend' ),
'desc' => __(
'Enter the password for the Basic Auth authentication.',
'wp-user-frontend'
),
'type' => 'text',
'callback' => 'wpuf_settings_password_preview',
'depends_on' => 'authentication_type',
'depends_on_value' => 'basic_auth',
],
[
'name' => 'header_auth_name',
'label' => __( 'Name', 'wp-user-frontend' ),
'desc' => __(
'Enter the name for the Header Auth authentication.',
'wp-user-frontend'
),
'type' => 'text',
'depends_on' => 'authentication_type',
'depends_on_value' => 'header_auth',
],
[
'name' => 'header_auth_value',
'label' => __( 'Header Auth Value', 'wp-user-frontend' ),
'desc' => __(
'Enter the value for the Header Auth authentication.',
'wp-user-frontend'
),
'type' => 'text',
'callback' => 'wpuf_settings_password_preview',
'depends_on' => 'authentication_type',
'depends_on_value' => 'header_auth',
],
[
'name' => 'jwt_key_type',
'label' => __( 'JWT Key Type', 'wp-user-frontend' ),
'desc' => __(
'Select the type of JWT key for the JWT Auth authentication.',
'wp-user-frontend'
),
'type' => 'select',
'default' => 'passphrase',
'options' => [
'passphrase' => __( 'Passphrase', 'wp-user-frontend' ),
'pem_key' => __( 'PEM Key', 'wp-user-frontend' ),
],
'depends_on' => 'authentication_type',
'depends_on_value' => 'jwt_auth',
],
[
'name' => 'jwt_key_passphrase',
'label' => __( 'Passphrase', 'wp-user-frontend' ),
'desc' => __(
'Enter the passphrase for the JWT Auth authentication.',
'wp-user-frontend'
),
'type' => 'text',
'callback' => 'wpuf_settings_password_preview',
'depends_on' => [
'authentication_type' => 'jwt_auth',
'jwt_key_type' => 'passphrase'
],
],
[
'name' => 'jwt_key_pem_key',
'label' => __( 'PEM Key', 'wp-user-frontend' ),
'desc' => __(
'Enter the PEM key for the JWT Auth authentication.',
'wp-user-frontend'
),
'type' => 'text',
'callback' => 'wpuf_settings_password_preview',
'depends_on' => [
'authentication_type' => 'jwt_auth',
'jwt_key_type' => 'pem_key',
],
],
],
];
return array_merge( $fields, $settings );
}
public function add_n8n_settings_fields( $fields ) {
$settings = [
'n8n' => [
[
'name' => 'authentication_type',
'label' => __( 'Authentication Type', 'wp-user-frontend' ),
'desc' => __(
'Select the authentication type for the N8N integration.',
'wp-user-frontend'
),
'type' => 'select',
'default' => 'none',
'options' => [
'none' => __( 'None', 'wp-user-frontend' ),
'basic_auth' => __( 'Basic Auth', 'wp-user-frontend' ),
'header_auth' => __( 'Header Auth', 'wp-user-frontend' ),
'jwt_auth' => __( 'JWT Auth', 'wp-user-frontend' ),
],
],
[
'name' => 'basic_auth_username',
'label' => __( 'Basic Auth Username', 'wp-user-frontend' ),
'desc' => __(
'Enter the username for the Basic Auth authentication.',
'wp-user-frontend'
),
'type' => 'text',
'depends_on' => 'authentication_type',
'depends_on_value' => 'basic_auth',
],
[
'name' => 'basic_auth_password',
'label' => __( 'Basic Auth Password', 'wp-user-frontend' ),
'desc' => __(
'Enter the password for the Basic Auth authentication.',
'wp-user-frontend'
),
'type' => 'text',
'callback' => 'wpuf_settings_password_preview',
'depends_on' => 'authentication_type',
'depends_on_value' => 'basic_auth',
],
[
'name' => 'header_auth_name',
'label' => __( 'Name', 'wp-user-frontend' ),
'desc' => __(
'Enter the name for the Header Auth authentication.',
'wp-user-frontend'
),
'type' => 'text',
'depends_on' => 'authentication_type',
'depends_on_value' => 'header_auth',
],
[
'name' => 'header_auth_value',
'label' => __( 'Header Auth Value', 'wp-user-frontend' ),
'desc' => __(
'Enter the value for the Header Auth authentication.',
'wp-user-frontend'
),
'type' => 'text',
'callback' => 'wpuf_settings_password_preview',
'depends_on' => 'authentication_type',
'depends_on_value' => 'header_auth',
],
[
'name' => 'jwt_key_type',
'label' => __( 'JWT Key Type', 'wp-user-frontend' ),
'desc' => __(
'Select the type of JWT key for the JWT Auth authentication.',
'wp-user-frontend'
),
'type' => 'select',
'default' => 'passphrase',
'options' => [
'passphrase' => __( 'Passphrase', 'wp-user-frontend' ),
'pem_key' => __( 'PEM Key', 'wp-user-frontend' ),
],
'depends_on' => 'authentication_type',
'depends_on_value' => 'jwt_auth',
],
[
'name' => 'jwt_key_passphrase',
'label' => __( 'Passphrase', 'wp-user-frontend' ),
'desc' => __(
'Enter the passphrase for the JWT Auth authentication.',
'wp-user-frontend'
),
'type' => 'text',
'callback' => 'wpuf_settings_password_preview',
'depends_on' => [
'authentication_type' => 'jwt_auth',
'jwt_key_type' => 'passphrase',
],
],
[
'name' => 'jwt_key_pem_key',
'label' => __( 'PEM Key', 'wp-user-frontend' ),
'desc' => __(
'Enter the PEM key for the JWT Auth authentication.',
'wp-user-frontend'
),
'type' => 'text',
'callback' => 'wpuf_settings_password_preview',
'depends_on' => [
'authentication_type' => 'jwt_auth',
'jwt_key_type' => 'pem_key',
],
],
],
];
return array_merge( $fields, $settings );
}
🧰 Tools
🪛 GitHub Check: Run PHPCS inspection

[failure] 272-272:
There should be a comma after the last array item in a multi-line array.


[failure] 239-239:
Multi-line function call not indented correctly; expected 24 spaces but found 28

🤖 Prompt for AI Agents
in includes/Integrations/WPUF_N8N_Integration.php around lines 180 to 293, PHPCS
flagged WordPress coding-standards formatting issues; adjust indentation and
spacing to match WP standards: use 1 tab per indent level, align array
keys/values with single space around =>, ensure multiline arrays use trailing
commas on last item, wrap long function argument lists and array entries to
respect 80-120 char limits, place closing array brackets and parentheses on
their own lines and ensure consistent blank lines between blocks; run phpcs
--standard=WordPress and apply its suggested fixes to verify.

Comment on lines +354 to +374
private function create_jwt_token( $secret_key ) {
// Simple JWT implementation - you might want to use a proper JWT library
$header = json_encode( [
'typ' => 'JWT',
'alg' => 'HS256'
] );

$payload = json_encode( [
'iat' => time(),
'exp' => time() + 3600, // 1 hour expiration
'iss' => get_site_url(),
] );

$base64_header = str_replace( ['+', '/', '='], ['-', '_', ''], base64_encode( $header ) );
$base64_payload = str_replace( ['+', '/', '='], ['-', '_', ''], base64_encode( $payload ) );

$signature = hash_hmac( 'sha256', $base64_header . '.' . $base64_payload, $secret_key, true );
$base64_signature = str_replace( ['+', '/', '='], ['-', '_', ''], base64_encode( $signature ) );

return $base64_header . '.' . $base64_payload . '.' . $base64_signature;
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Use a proper JWT library instead of custom implementation.

The custom JWT implementation works for basic cases but lacks important features and may have security implications. The comment on Line 355 acknowledges this concern.

Consider using a well-tested JWT library like firebase/php-jwt:

composer require firebase/php-jwt

Then replace the custom implementation:

use Firebase\JWT\JWT;

private function create_jwt_token( $secret_key ) {
    $payload = [
        'iat' => time(),
        'exp' => time() + 3600,
        'iss' => get_site_url(),
    ];
    
    try {
        return JWT::encode( $payload, $secret_key, 'HS256' );
    } catch ( \Exception $e ) {
        \WP_User_Frontend::log( 'n8n', 'JWT generation failed: ' . $e->getMessage() );
        return false;
    }
}

This provides:

  • Proper JWT standard compliance
  • Better error handling
  • Support for various algorithms
  • Security updates from the library maintainers
🧰 Tools
🪛 GitHub Check: Run PHPCS inspection

[warning] 371-371:
base64_encode() can be used to obfuscate code which is strongly discouraged. Please verify that the function is used for benign reasons.


[warning] 368-368:
base64_encode() can be used to obfuscate code which is strongly discouraged. Please verify that the function is used for benign reasons.


[warning] 367-367:
base64_encode() can be used to obfuscate code which is strongly discouraged. Please verify that the function is used for benign reasons.


[failure] 367-367:
Expected 1 space after the array opener in a single line array. Found: no spaces


[failure] 365-365:
Closing parenthesis of a multi-line function call must be on a line by itself


[failure] 361-361:
Opening parenthesis of a multi-line function call must be the last content on the line


[warning] 361-361:
json_encode() is discouraged. Use wp_json_encode() instead.


[failure] 359-359:
Closing parenthesis of a multi-line function call must be on a line by itself


[failure] 358-358:
There should be a comma after the last array item in a multi-line array.


[failure] 356-356:
Opening parenthesis of a multi-line function call must be the last content on the line


[warning] 356-356:
json_encode() is discouraged. Use wp_json_encode() instead.

🤖 Prompt for AI Agents
In includes/Integrations/WPUF_N8N_Integration.php around lines 354 to 374,
replace the custom JWT creation with a call to a vetted library (e.g.,
firebase/php-jwt): add the library via composer, import the JWT class at top of
the file, and update create_jwt_token to build the payload and call
JWT::encode($payload, $secret_key, 'HS256'); wrap the encode call in a try/catch
to log exceptions (WP_User_Frontend::log or process logger) and return false on
failure; ensure the function’s return semantics reflect string on success or
false on error.

⚠️ Potential issue | 🟡 Minor

Fix coding standards violations in JWT method.

WordPress coding standards require using wp_json_encode() instead of json_encode() and proper formatting for multi-line function calls.

Apply these fixes:

-            $header = json_encode( [
+            $header = wp_json_encode(
+                [
                 'typ' => 'JWT',
-                'alg' => 'HS256'
-            ] );
+                'alg' => 'HS256',
+                ]
+            );

-            $payload = json_encode( [
+            $payload = wp_json_encode(
+                [
                 'iat' => time(),
                 'exp' => time() + 3600, // 1 hour expiration
                 'iss' => get_site_url(),
-            ] );
+                ]
+            );

-            $base64_header = str_replace( ['+', '/', '='], ['-', '_', ''], base64_encode( $header ) );
+            $base64_header = str_replace( [ '+', '/', '=' ], [ '-', '_', '' ], base64_encode( $header ) );

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

🧰 Tools
🪛 GitHub Check: Run PHPCS inspection

[warning] 371-371:
base64_encode() can be used to obfuscate code which is strongly discouraged. Please verify that the function is used for benign reasons.


[warning] 368-368:
base64_encode() can be used to obfuscate code which is strongly discouraged. Please verify that the function is used for benign reasons.


[warning] 367-367:
base64_encode() can be used to obfuscate code which is strongly discouraged. Please verify that the function is used for benign reasons.


[failure] 367-367:
Expected 1 space after the array opener in a single line array. Found: no spaces


[failure] 365-365:
Closing parenthesis of a multi-line function call must be on a line by itself


[failure] 361-361:
Opening parenthesis of a multi-line function call must be the last content on the line


[warning] 361-361:
json_encode() is discouraged. Use wp_json_encode() instead.


[failure] 359-359:
Closing parenthesis of a multi-line function call must be on a line by itself


[failure] 358-358:
There should be a comma after the last array item in a multi-line array.


[failure] 356-356:
Opening parenthesis of a multi-line function call must be the last content on the line


[warning] 356-356:
json_encode() is discouraged. Use wp_json_encode() instead.

🤖 Prompt for AI Agents
In includes/Integrations/WPUF_N8N_Integration.php around lines 354 to 374, the
create_jwt_token method uses json_encode and has compact multi-line
array/function calls that violate WP coding standards; replace json_encode()
with wp_json_encode() for both $header and $payload and reformat the multi-line
array and function calls to follow WP formatting (each array element and
function argument on its own line with proper indentation and trailing commas
where appropriate) while keeping the same logic and return value.

@Rubaiyat-E-Mohammad Rubaiyat-E-Mohammad added QA Approved This PR is approved by the QA team and removed needs: testing labels Nov 6, 2025
@Rubaiyat-E-Mohammad
Copy link
Contributor

Input box for turnstile site key and secret key is not visible in settings page. @sapayth vai

image

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

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
Lib/WeDevs_Settings_API.php (1)

873-873: Dependency logic breaks for checkboxes and radios.

The comparison $depends_on.val() !== expected_value on lines 873 and 924 fails for checkboxes and radios. For checkboxes, .val() returns the value attribute ("on" by default) regardless of checked state. For radios, you must select the checked radio first.

This issue was previously flagged with a detailed fix that has not been implemented.

Apply the patch from the previous review to handle checkbox and radio types correctly by checking the checked state for checkboxes and selecting the checked radio for radio groups before comparing values.

Also applies to: 924-924

🧹 Nitpick comments (2)
Lib/WeDevs_Settings_API.php (2)

847-864: Extract duplicated selector logic into a helper function.

The selector fallback logic (trying multiple patterns to find the dependency field) is duplicated in both the initial dependency check and the checkAllDependencies() function. This makes maintenance harder and increases code size.

Consider extracting this logic into a helper function:

+                // Helper function to find dependency field
+                function findDependencyField(field_name) {
+                    var $field = $("input[id*='"+ field_name +"'], select[id*='"+ field_name +"']");
+                    if ($field.length === 0) {
+                        $field = $("input[name*='["+ field_name +"]'], select[name*='["+ field_name +"]']");
+                    }
+                    if ($field.length === 0) {
+                        $field = $("input[id*='["+ field_name +"]'], select[id*='["+ field_name +"]']");
+                    }
+                    if ($field.length === 0) {
+                        $field = $("input[id*='"+ field_name +"'], select[id*='"+ field_name +"']");
+                    }
+                    return $field;
+                }

Then use findDependencyField(field_name) in both locations instead of repeating the selector logic.

Also applies to: 907-922


902-936: Function defined inside loop creates unnecessary closures.

The checkAllDependencies() function is defined inside the .each() loop, creating a new function instance for each field with dependencies. While this works due to closures capturing $this and dependencies, it's inefficient and could impact performance with many dependent fields.

Consider refactoring to avoid creating multiple function instances. One approach is to store the dependencies and target element as data attributes or in a map, then use a single shared function.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 79d483e and 70716ae.

📒 Files selected for processing (3)
  • Lib/WeDevs_Settings_API.php (5 hunks)
  • assets/js/wpuf-form-builder.js (1 hunks)
  • wpuf-functions.php (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • assets/js/wpuf-form-builder.js
  • wpuf-functions.php
🧰 Additional context used
🧬 Code graph analysis (1)
Lib/WeDevs_Settings_API.php (1)
wpuf-functions.php (1)
  • wpuf_get_pro_preview_html (4698-4704)

$value = esc_attr( $this->get_option( $args['id'], $args['section'], $args['std'] ) );
$disabled = ! empty( $args['is_pro_preview'] ) && $args['is_pro_preview'] ? 'disabled' : '';
$size = isset( $args['size'] ) && ! is_null( $args['size'] ) ? $args['size'] : 'regular';
$depends_on = ! empty( $args['depends_on'] ) ? $args['depends_on'] : '';
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Missing 'placeholder' attribute in wp_kses allowed attributes.

The placeholder attribute is used in the sprintf on line 195 (set on line 181), but it's not included in the wp_kses allowed attributes list on line 204. This will cause the placeholder to be stripped from the output.

Apply this diff to add the missing attribute:

-        echo wp_kses( $html, array('input' => ['type' => [],'class' => [],'id' => [],'name' => [],'value' => [],'disabled' => [],'data-depends-on' => [],'data-depends-on-value' => []], 'p' => ['class' => []], 'div' => ['class' => []], 'a' => ['href' => [],'target' => [],'class' => []], 'span' => ['class' => []], 'svg' => ['width' => [],'height' => [],'viewBox' => [],'fill' => [],'xmlns' => [],],));
+        echo wp_kses( $html, array('input' => ['type' => [],'class' => [],'id' => [],'name' => [],'value' => [],'placeholder' => [],'disabled' => [],'data-depends-on' => [],'data-depends-on-value' => []], 'p' => ['class' => []], 'div' => ['class' => []], 'a' => ['href' => [],'target' => [],'class' => []], 'span' => ['class' => []], 'svg' => ['width' => [],'height' => [],'viewBox' => [],'fill' => [],'xmlns' => [],],));
📝 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
echo wp_kses( $html, array('input' => ['type' => [],'class' => [],'id' => [],'name' => [],'value' => [],'disabled' => [],'data-depends-on' => [],'data-depends-on-value' => []], 'p' => ['class' => []], 'div' => ['class' => []], 'a' => ['href' => [],'target' => [],'class' => []], 'span' => ['class' => []], 'svg' => ['width' => [],'height' => [],'viewBox' => [],'fill' => [],'xmlns' => [],],));
echo wp_kses( $html, array('input' => ['type' => [],'class' => [],'id' => [],'name' => [],'value' => [],'placeholder' => [],'disabled' => [],'data-depends-on' => [],'data-depends-on-value' => []], 'p' => ['class' => []], 'div' => ['class' => []], 'a' => ['href' => [],'target' => [],'class' => []], 'span' => ['class' => []], 'svg' => ['width' => [],'height' => [],'viewBox' => [],'fill' => [],'xmlns' => [],],));
🤖 Prompt for AI Agents
In Lib/WeDevs_Settings_API.php around line 204, the wp_kses allowed-attributes
list for the input tag is missing the 'placeholder' attribute causing
placeholder text (set earlier) to be stripped; update the allowed attributes
array for 'input' to include 'placeholder' => [] so wp_kses will preserve
placeholder values in the rendered HTML.

@sapayth
Copy link
Member Author

sapayth commented Nov 17, 2025

Input box for turnstile site key and secret key is not visible in settings page. @sapayth vai

image

please have a look now @Rubaiyat-E-Mohammad bhai

Fix field visibility logic for checkbox dependencies. When a checkbox
has an empty expected_value, dependent fields now correctly show when
the checkbox is checked (instead of when unchecked).

This fixes the issue where fields like 'Turnstile Site Key' and
'Turnstile Secret Key' were hiding when 'Enable Turnstile' checkbox
was checked, when they should have been visible.

The fix applies proper checkbox state detection using :checked selector
and handles both empty and non-empty expected values appropriately.

Also includes CSS cleanup (removing duplicate webkit prefixes) and
language file updates.
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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
languages/wp-user-frontend.pot (1)

3040-3045: Fix awkward help text grammar

Improve clarity of “If selected a form template …” string.

Apply in source (then regenerate POT):

- "If selected a form template, it will try to execute that integration options when new post created and updated."
+ "If a form template is selected, its integration options will run when a post is created or updated."
♻️ Duplicate comments (1)
Lib/WeDevs_Settings_API.php (1)

184-204: Missing 'placeholder' attribute in wp_kses (duplicate issue).

The placeholder attribute is used in the sprintf on line 195 (set on line 181), but it's still not included in the wp_kses allowed attributes list on line 204. This will cause the placeholder to be stripped from the output.

Apply this diff to add the missing attribute:

-        echo wp_kses( $html, array('input' => ['type' => [],'class' => [],'id' => [],'name' => [],'value' => [],'disabled' => [],'data-depends-on' => [],'data-depends-on-value' => []], 'p' => ['class' => []], 'div' => ['class' => []], 'a' => ['href' => [],'target' => [],'class' => []], 'span' => ['class' => []], 'svg' => ['width' => [],'height' => [],'viewBox' => [],'fill' => [],'xmlns' => [],],));
+        echo wp_kses( $html, array('input' => ['type' => [],'class' => [],'id' => [],'name' => [],'value' => [],'placeholder' => [],'disabled' => [],'data-depends-on' => [],'data-depends-on-value' => []], 'p' => ['class' => []], 'div' => ['class' => []], 'a' => ['href' => [],'target' => [],'class' => []], 'span' => ['class' => []], 'svg' => ['width' => [],'height' => [],'viewBox' => [],'fill' => [],'xmlns' => [],],));
🧹 Nitpick comments (1)
Lib/WeDevs_Settings_API.php (1)

846-868: Significant code duplication in dependency field selectors.

The selector logic for finding dependency fields is duplicated between the initial check (lines 846-868) and the checkAllDependencies() function (lines 921-938). This makes the code harder to maintain.

Consider extracting the selector logic into a helper function:

+                // Helper function to find dependency field
+                function findDependencyField(field_name) {
+                    var $field = $("input[id*='"+ field_name +"'], select[id*='"+ field_name +"']");
+                    if ($field.length === 0) {
+                        $field = $("input[name*='["+ field_name +"]'], select[name*='["+ field_name +"]']");
+                    }
+                    if ($field.length === 0) {
+                        $field = $("input[id*='["+ field_name +"]'], select[id*='["+ field_name +"]']");
+                    }
+                    if ($field.length === 0) {
+                        $field = $("input[id*='"+ field_name +"'], select[id*='"+ field_name +"']");
+                    }
+                    return $field;
+                }

Then replace both instances with calls to findDependencyField(field_name).

Also applies to: 921-938

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 70716ae and 78eb50f.

📒 Files selected for processing (4)
  • Lib/WeDevs_Settings_API.php (5 hunks)
  • assets/css/admin/form-builder.css (2 hunks)
  • assets/css/ai-form-builder.css (2 hunks)
  • languages/wp-user-frontend.pot (30 hunks)
✅ Files skipped from review due to trivial changes (1)
  • assets/css/ai-form-builder.css
🧰 Additional context used
🧬 Code graph analysis (1)
Lib/WeDevs_Settings_API.php (1)
wpuf-functions.php (1)
  • wpuf_get_pro_preview_html (4698-4704)
🔇 Additional comments (5)
assets/css/admin/form-builder.css (1)

3025-3025: ✓ CSS Modernization: Good use of standard backdrop-filter property.

The changes correctly replace vendor-prefixed CSS with the modern standard backdrop-filter property. Both occurrences (lines 3025 and 3045) in the .wpuf-glass and .wpuf-glass.wpuf-btn-active rules now use the standard property, which is well-supported across modern browsers and aligns with CSS standards.

No behavioral changes; this is a clean upgrade from vendor prefixes to standardized CSS.

Also applies to: 3045-3045

languages/wp-user-frontend.pot (2)

7-7: POT timestamp looks correct

POT-Creation-Date updated to 2025-11-17T05:45:00Z. No issues.


208-215: Reference-only updates acknowledged

These appear to be reference/offset churn with unchanged msgids. Safe to ship.

Also applies to: 529-551, 556-559, 608-612, 674-676, 695-698, 706-724, 731-744, 772-775, 787-790, 838-844, 875-878, 896-898, 914-916, 981-983, 985-987, 990-992, 1006-1012

Lib/WeDevs_Settings_API.php (2)

144-144: LGTM!

The addition of depends_on_value to the args array follows the same pattern as the existing depends_on field and properly handles optional values.


385-409: LGTM!

The select field changes mirror the text field implementation correctly, with proper array dependency handling and data attribute sanitization.

Comment on lines +7204 to +7306
#: includes/Integrations/WPUF_N8N_Integration.php:163
#: includes/Integrations/WPUF_N8N_Integration.php:309
msgid "N8N"
msgstr ""

#: includes/Integrations/WPUF_N8N_Integration.php:185
msgid "Authentication Type"
msgstr ""

#: includes/Integrations/WPUF_N8N_Integration.php:186
msgid "Select the authentication type for the N8N integration."
msgstr ""

#: includes/Integrations/WPUF_N8N_Integration.php:193 wpuf-functions.php:3682
msgid "None"
msgstr ""

#: includes/Integrations/WPUF_N8N_Integration.php:194
msgid "Basic Auth"
msgstr ""

#: includes/Integrations/WPUF_N8N_Integration.php:195
msgid "Header Auth"
msgstr ""

#: includes/Integrations/WPUF_N8N_Integration.php:196
msgid "JWT Auth"
msgstr ""

#: includes/Integrations/WPUF_N8N_Integration.php:201
msgid "Basic Auth Username"
msgstr ""

#: includes/Integrations/WPUF_N8N_Integration.php:202
msgid "Enter the username for the Basic Auth authentication."
msgstr ""

#: includes/Integrations/WPUF_N8N_Integration.php:212
msgid "Basic Auth Password"
msgstr ""

#: includes/Integrations/WPUF_N8N_Integration.php:213
msgid "Enter the password for the Basic Auth authentication."
msgstr ""

#: includes/Integrations/WPUF_N8N_Integration.php:225
msgid "Enter the name for the Header Auth authentication."
msgstr ""

#: includes/Integrations/WPUF_N8N_Integration.php:235
msgid "Header Auth Value"
msgstr ""

#: includes/Integrations/WPUF_N8N_Integration.php:236
msgid "Enter the value for the Header Auth authentication."
msgstr ""

#: includes/Integrations/WPUF_N8N_Integration.php:247
msgid "JWT Key Type"
msgstr ""

#: includes/Integrations/WPUF_N8N_Integration.php:248
msgid "Select the type of JWT key for the JWT Auth authentication."
msgstr ""

#: includes/Integrations/WPUF_N8N_Integration.php:255
#: includes/Integrations/WPUF_N8N_Integration.php:263
msgid "Passphrase"
msgstr ""

#: includes/Integrations/WPUF_N8N_Integration.php:256
#: includes/Integrations/WPUF_N8N_Integration.php:277
msgid "PEM Key"
msgstr ""

#: includes/Integrations/WPUF_N8N_Integration.php:264
msgid "Enter the passphrase for the JWT Auth authentication."
msgstr ""

#: includes/Integrations/WPUF_N8N_Integration.php:278
msgid "Enter the PEM key for the JWT Auth authentication."
msgstr ""

#: includes/Integrations/WPUF_N8N_Integration.php:330
msgid "Enable N8N Integration"
msgstr ""

#: includes/Integrations/WPUF_N8N_Integration.php:332
msgid "Enable N8N integration"
msgstr ""

#: includes/Integrations/WPUF_N8N_Integration.php:337
msgid "Webhook URL"
msgstr ""

#: includes/Integrations/WPUF_N8N_Integration.php:339
msgid "Enter the N8N webhook URL to send form data when posts are submitted"
msgstr ""

#: includes/Integrations/WPUF_N8N_Integration.php:340
msgid "https://your-n8n-instance.com/webhook/your-webhook-id"
msgstr ""

Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

n8n brand, capitalization, and context consistency

  • Use “n8n” (lowercase) consistently.
  • Unify label/description casing: “Enable n8n integration”.
  • Disambiguate “Name” for header auth; prefer “Header Name” or add msgctxt to avoid collision with generic “Name”.

Proposed source changes (then regenerate POT):

- __( 'N8N', 'wp-user-frontend' )
+ __( 'n8n', 'wp-user-frontend' )

- __( 'Enable N8N Integration', 'wp-user-frontend' )
+ __( 'Enable n8n integration', 'wp-user-frontend' )

- __( 'Enable N8N integration', 'wp-user-frontend' )
+ __( 'Enable n8n integration', 'wp-user-frontend' )

- __( 'Webhook URL', 'wp-user-frontend' )
+ __( 'Webhook URL', 'wp-user-frontend' ) // keep label

- __( 'Enter the N8N webhook URL to send form data when posts are submitted', 'wp-user-frontend' )
+ __( 'Enter the n8n webhook URL to send form data when posts are submitted', 'wp-user-frontend' )

- __( 'Name', 'wp-user-frontend' ) // used as Header Auth name
+ _x( 'Header Name', 'n8n header authorization key label', 'wp-user-frontend' )

- __( 'Authentication Type', 'wp-user-frontend' ) // keep
+ _x( 'Authentication Type', 'n8n integration setting', 'wp-user-frontend' )

If you prefer to keep “Name”, add msgctxt instead:

_x( 'Name', 'n8n header authorization key label', 'wp-user-frontend' );

Also update the sample text:

- "https://your-n8n-instance.com/webhook/your-webhook-id"
+ "https://your-n8n-instance.com/webhook/your-webhook-id"
# (no change to URL itself; only ensure surrounding descriptions use "n8n")

I can open a small follow-up PR touching includes/Integrations/WPUF_N8N_Integration.php to apply this.

🤖 Prompt for AI Agents
In languages/wp-user-frontend.pot around lines 7204 to 7306, update branding and
label consistency: change all "N8N" to "n8n" (e.g., msgid "N8N" -> "n8n"),
update labels to use sentence-style casing like "Enable n8n integration" and
"Enable n8n Integration" occurrences, disambiguate the generic "Name" used for
header auth by replacing it with "Header Name" (or use _x( 'Name', 'n8n header
authorization key label', 'wp-user-frontend' ) in the source to add msgctxt),
and update the sample webhook URL to use lowercase "n8n" (e.g.,
"https://your-n8n-instance.com/...") before regenerating the POT.

Comment on lines +870 to +892
if (expected_value === '' || expected_value === null || expected_value === undefined) {
// Empty expected value means "show when checked" (typical use case)
value_matches = is_checked;
} else {
$this.closest('tr').hide();
// Non-empty expected value means "show when checked with this value"
value_matches = is_checked && (current_value === expected_value || expected_value === 'on');
}
});
} else {
value_matches = current_value === expected_value;
}

if (!value_matches) {
all_dependencies_met = false;
}
}

// Show/hide based on all dependencies
if (all_dependencies_met) {
$this.closest('tr').show();
} else {
$depends_on.on('keyup change', function() {
if ($(this).val() === $this.data('depends-on-value')) {
$this.closest('tr').show();
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Radio button value comparison broken.

For radio buttons, .val() on a jQuery collection returns the value attribute of the first element, not the checked one. This prevents radio-based dependencies from working correctly.

The checkbox handling partially addresses the previous review's concerns, but radio buttons still need special treatment. Apply this diff to fix radio button handling in both the initial check and checkAllDependencies():

In the initial dependency check (around line 870):

                         dependency_fields[field_name] = $depends_on;
                         var current_value = $depends_on.val();
                         var is_checkbox = $depends_on.attr('type') === 'checkbox';
+                        var is_radio = $depends_on.attr('type') === 'radio';
                         var is_checked = is_checkbox ? $depends_on.is(':checked') : null;
                         
                         // For checkboxes, handle empty string as "checked" expectation
                         var value_matches = false;
                         if (is_checkbox) {
                             if (expected_value === '' || expected_value === null || expected_value === undefined) {
                                 // Empty expected value means "show when checked" (typical use case)
                                 value_matches = is_checked;
                             } else {
                                 // Non-empty expected value means "show when checked with this value"
                                 value_matches = is_checked && (current_value === expected_value || expected_value === 'on');
                             }
+                        } else if (is_radio) {
+                            // For radio buttons, get the value of the checked one
+                            var radio_name = $depends_on.attr('name');
+                            var checked_value = $('input[name="'+ radio_name +'"]:checked').val() || '';
+                            value_matches = checked_value === expected_value;
                         } else {
                             value_matches = current_value === expected_value;
                         }

In checkAllDependencies (around line 940):

                             var current_value = $depends_on.length > 0 ? $depends_on.val() : 'NOT_FOUND';
                             var is_checkbox = $depends_on.length > 0 && $depends_on.attr('type') === 'checkbox';
+                            var is_radio = $depends_on.length > 0 && $depends_on.attr('type') === 'radio';
                             var is_checked = is_checkbox ? $depends_on.is(':checked') : null;
                             
                             // For checkboxes, handle empty string as "checked" expectation
                             var value_matches = false;
                             if ($depends_on.length === 0) {
                                 value_matches = false;
                             } else if (is_checkbox) {
                                 if (expected_value === '' || expected_value === null || expected_value === undefined) {
                                     // Empty expected value means "show when checked" (typical use case)
                                     value_matches = is_checked;
                                 } else {
                                     // Non-empty expected value means "show when checked with this value"
                                     value_matches = is_checked && (current_value === expected_value || expected_value === 'on');
                                 }
+                            } else if (is_radio) {
+                                // For radio buttons, get the value of the checked one
+                                var radio_name = $depends_on.attr('name');
+                                var checked_value = $('input[name="'+ radio_name +'"]:checked').val() || '';
+                                value_matches = checked_value === expected_value;
                             } else {
                                 value_matches = current_value === expected_value;
                             }

Also applies to: 940-964

🤖 Prompt for AI Agents
In Lib/WeDevs_Settings_API.php around lines 870-892 and 940-964, radio-button
dependency checks use $depends_on.val() which returns the first element's value
instead of the checked radio's value; update both places to detect radio groups
(e.g. $depends_on.is(':radio') or $depends_on.filter(':radio').length) and when
radio inputs are present retrieve the value of the checked radio via
$depends_on.filter(':checked').val() (and treat absence as unchecked), then
perform comparisons against expected_value (mirroring checkbox logic: empty
expected_value means show when checked, otherwise compare checked value or
'on'), ensuring you branch for radio vs checkbox vs other inputs in both the
initial check and in checkAllDependencies().

@Rubaiyat-E-Mohammad Rubaiyat-E-Mohammad added QA Approved This PR is approved by the QA team and removed needs: testing labels Nov 18, 2025
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
wpuf-functions.php (1)

4043-4087: Critical issue from previous review remains unresolved.

The past review identified that this password preview field will corrupt the stored secret on form submission. The input on line 4079 binds the real option name to the masked preview value, so submitting the form will save the masked string (e.g., ab****yz) to the database instead of preserving the actual secret.

Please implement the fix provided in the previous review comment to avoid data corruption.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 78eb50f and 8c5dfd5.

📒 Files selected for processing (1)
  • wpuf-functions.php (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
wpuf-functions.php (1)
Lib/WeDevs_Settings_API.php (3)
  • WeDevs_Settings_API (13-984)
  • get_option (636-645)
  • get_field_description (162-170)

Comment on lines +4043 to +4087
/**
* Password preview field callback
*
* @param array $args Field arguments
* @since WPUF_PRO_SINCE
*/
function wpuf_settings_password_preview( $args ) {
wpuf_require_once( WPUF_ROOT . '/Lib/WeDevs_Settings_API.php' );

$settings = new WeDevs_Settings_API();
$value = $settings->get_option( $args['id'], $args['section'], $args['std'] );
$disabled = ! empty( $args['is_pro_preview'] ) && $args['is_pro_preview'] ? 'disabled' : '';
$size = isset( $args['size'] ) && ! is_null( $args['size'] ) ? $args['size'] : 'regular';

// Create masked preview of the password
$preview_value = '';
if ( ! empty( $value ) ) {
$length = strlen( $value );
if ( $length >= 4 ) {
$preview_value = substr( $value, 0, 2 ) . str_repeat( '*', $length - 4 ) . substr( $value, -2 );
} else {
$preview_value = str_repeat( '*', $length );
}
}

$depends_on = ! empty( $args['depends_on'] ) ? $args['depends_on'] : '';
$depends_on_value = ! empty( $args['depends_on_value'] ) ? $args['depends_on_value'] : '';

// Handle array dependencies
if (is_array($depends_on)) {
$depends_on_json = esc_attr( json_encode($depends_on) );
$depends_on_value = ''; // Not used for array format
} else {
$depends_on_json = esc_attr( $depends_on );
}

$html = sprintf( '<input type="text" class="%1$s-text" id="%2$s[%3$s]" name="%2$s[%3$s]" value="%4$s" %5$s data-depends-on=\'%6$s\' data-depends-on-value="%7$s"/>', $size, $args['section'], $args['id'], $preview_value, $disabled, $depends_on_json, esc_attr( $depends_on_value ) );
$html .= $settings->get_field_description( $args );

if ( ! empty( $args['is_pro_preview'] ) && $args['is_pro_preview'] ) {
$html .= wpuf_get_pro_preview_html();
}

echo wp_kses( $html, array( 'input' => array( 'type' => array(), 'class' => array(), 'id' => array(), 'name' => array(), 'value' => array(), 'readonly' => array(), 'style' => array(), 'disabled' => array(), 'data-depends-on' => array(), 'data-depends-on-value' => array() ), 'p' => array( 'class' => array() ), 'div' => array( 'class' => array() ), 'a' => array( 'href' => array(), 'target' => array(), 'class' => array() ), 'span' => array( 'class' => array() ), 'svg' => array( 'width' => array(), 'height' => array(), 'viewBox' => array(), 'fill' => array(), 'xmlns' => array() ), 'path' => array( 'd' => array(), 'fill' => array() ) ) );
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Remove duplicate function declaration.

According to the AI summary, this function wpuf_settings_password_preview is declared twice in this file. Duplicate function declarations can cause maintenance issues and potential conflicts.

Please remove the duplicate declaration and keep only one instance.

Based on learnings.

🤖 Prompt for AI Agents
In wpuf-functions.php around lines 4043-4087 there's a duplicate declaration of
function wpuf_settings_password_preview; remove the other duplicate declaration
(whichever is outside these lines) so only a single definition remains, and
ensure any helper logic or differences from the duplicate are merged into the
kept version before deleting; finally run a quick search for
wpuf_settings_password_preview to confirm only one declaration exists and run
lint/tests to verify no breakage.

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)
languages/wp-user-frontend.pot (1)

7216-7316: n8n branding and header-auth label context still need adjustment

The N8N integration strings here still show the earlier issues:

  • Brand capitalization: official branding is n8n, but msgids use "N8N" ("N8N", "Enable N8N Integration", "Enable N8N integration", "Enter the N8N webhook URL..."). Consider switching to "n8n" consistently.
  • Header Auth label: the generic "Name" label (referenced at line 861 and here via includes/Integrations/WPUF_N8N_Integration.php:224) is reused in other contexts, which may confuse translators and users. Renaming to "Header Name" or adding a context (msgctxt) in the PHP source for the n8n header key would disambiguate it.
  • If you keep "Authentication Type" generic, consider adding a msgctxt in PHP for the n8n settings usage.

These changes should be done in the PHP source (e.g., includes/Integrations/WPUF_N8N_Integration.php), then the POT regenerated so the msgids match. This mirrors the earlier review feedback and remains unresolved.

🧹 Nitpick comments (1)
assets/css/admin.css (1)

732-740: CSS rule additions look good, but consider reducing property duplication.

The new selectors .form-table th span.pro-icon and .form-table label span.pro-icon redefine display: inline-flex, align-items: center, and vertical-align: middle—all already declared in the parent span.pro-icon rule (line 720–731). Only the new adjustments (line-height: 0, position: relative, top: -1px) are needed here.

Apply this diff to eliminate duplication:

 .form-table th span.pro-icon,
 .form-table label span.pro-icon {
-  display: inline-flex;
-  align-items: center;
-  vertical-align: middle;
   line-height: 0;
   position: relative;
   top: -1px;
 }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8c5dfd5 and 585ff8f.

📒 Files selected for processing (5)
  • admin/form-builder/assets/js/form-builder.js (1 hunks)
  • assets/css/admin.css (1 hunks)
  • assets/css/admin/form-builder.css (5 hunks)
  • assets/css/ai-form-builder.css (5 hunks)
  • languages/wp-user-frontend.pot (35 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • assets/css/admin/form-builder.css
🔇 Additional comments (7)
admin/form-builder/assets/js/form-builder.js (1)

1292-1299: LGTM! Clean integration for N8N webhook URL dependency.

The new n8n_webhook_url field configuration correctly follows the established pattern for conditional field visibility. The dependency logic appropriately shows the webhook URL input only when N8N integration is enabled, and it will work seamlessly with the existing FormDependencyHandler class.

languages/wp-user-frontend.pot (4)

7-7: POT header regeneration looks correct

POT-Creation-Date was updated as expected for a regenerated catalog; no issues here.


208-215: Reference/line-number shifts only

The #: ... source references updated here (and similarly throughout the file) only adjust file/line mappings without changing any msgid text, so there’s no functional or localization impact.


1866-2025: AI error and status messages are well-structured

The new AI-related strings (includes/AI/Config.php and includes/AI/RestController.php) are clear, consistently phrased, and use printf-style placeholders (%s, %d) correctly, which should be safe for translators and runtime formatting.


457-462: Issue #1257: required strings now present in POT

For the translation coverage issue:

  • "Preview" (lines 457–462) is present and referenced from templates/dashboard/posts.php:167.
  • "View" (lines 8642–8643) is present and referenced from templates/dashboard/posts.php:164 (Status column options).
  • "Unlimited" (lines 7469–7472) is present and referenced from templates/dashboard/subscription.php:188 and related paths.

This satisfies the POT-side requirement from issue #1257; these UI strings are now available for translators.

Also applies to: 7469-7472, 8642-8643

assets/css/ai-form-builder.css (2)

1097-1097: Well done: Vendor prefix removal for backdrop-filter.

The removal of -webkit-backdrop-filter from transition-property declarations (e.g., lines 1097, 1884, 2573) and the use of standard backdrop-filter throughout (lines 3025, 3045) aligns with modern browser support. This is a solid cleanup that reduces CSS bloat without compromising compatibility.

Also applies to: 1884-1884, 2573-2573, 3025-3025, 3045-3045


5331-5333: Utilities are consumed; confirm focus-variant intent.

Found direct usages:

  • assets/js/components/FormsList.vue:601 — wpuf-bg-emerald-50
  • assets/js/components/FormSuccessStage.vue:333 — wpuf-bg-emerald-50
  • assets/js/components/subscriptions/SectionInputField.vue:310 — wpuf-bg-emerald-50/50, wpuf-backdrop-blur-sm

Compiled/minified assets include the focus variant definition (focus:wpuf-bg-emerald-700) but no template references were detected — confirm if that focus utility is intentionally retained (used dynamically) or can be removed to avoid extra CSS weight.

Comment on lines 741 to 746
/* span.pro-icon.icon-white svg path {
fill: #fff;
fill: #fff;
} */
/* label span.pro-icon svg path {
fill: #10b981;
fill: #10b981;
} */
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Remove or explain commented-out code.

Lines 741–746 contain two commented-out CSS rules for icon fill styling. Either remove this dead code or add an inline comment explaining why it's disabled (e.g., TODO, deprecated feature, etc.).

Apply this diff to clean up:

-/* span.pro-icon.icon-white svg path {
-    fill: #fff;
-} */
-/* label span.pro-icon svg path {
-    fill: #10b981;
-} */
📝 Committable suggestion

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

Suggested change
/* span.pro-icon.icon-white svg path {
fill: #fff;
fill: #fff;
} */
/* label span.pro-icon svg path {
fill: #10b981;
fill: #10b981;
} */
🤖 Prompt for AI Agents
In assets/css/admin.css around lines 741 to 746, there are two commented-out CSS
rules for icon fill styling; either remove these dead lines or replace them with
a brief inline comment explaining why they're disabled (for example: "TODO:
deprecated - kept for reference", "disabled due to design change X on DATE", or
link to an issue/PR). Update the file by deleting the commented rules if they
are no longer needed, or leave a single-line comment above them that states the
reason and references any relevant ticket, then save.

Comment on lines +5475 to 5482
#: includes/Free/Form_Element.php:188 includes/Free/Free_Loader.php:1585
msgid "Multistep Progressbar Type"
msgstr ""

#: includes/Free/Form_Element.php:198 includes/Free/Free_Loader.php:1589
#: includes/Free/Form_Element.php:198 includes/Free/Free_Loader.php:1587
msgid "Choose how you want the progressbar"
msgstr ""

Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Polish a few new UI strings for grammar and clarity

These new labels/descriptions are understandable but could be tightened for correctness:

  • Line 5475: "Multistep Progressbar Type" → consider "Multi-step Progress Bar Type".
  • Line 5480: "Choose how you want the progressbar" → consider "Choose how you want the progress bar to appear".
  • Line 9399: "After successfully submit, where the page will redirect to" → consider "After successful submission, where should the page redirect to?" or "After successful submission, where the page will redirect to".
  • Line 9489: "Choose who can submit post" → consider "Choose who can submit posts".

These are minor UX copy fixes but will make the settings panel read more professionally.

Also applies to: 9399-9401, 9488-9491

🤖 Prompt for AI Agents
languages/wp-user-frontend.pot lines 5475-5482, 9399-9401, 9488-9491: replace
the indicated message strings to improve grammar and clarity — change "Multistep
Progressbar Type" to "Multi-step Progress Bar Type", change "Choose how you want
the progressbar" to "Choose how you want the progress bar to appear", change
"After successfully submit, where the page will redirect to" to "After
successful submission, where should the page redirect to?" (or the alternative
"After successful submission, where the page will redirect to"), and change
"Choose who can submit post" to "Choose who can submit posts"; update the msgstr
entries accordingly in each location.

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

Labels

QA Approved This PR is approved by the QA team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants