Skip to content

feature: account page elementor widget#1826

Open
sapayth wants to merge 3 commits intoweDevsOfficial:developfrom
sapayth:feature/account_page_elementor_widget
Open

feature: account page elementor widget#1826
sapayth wants to merge 3 commits intoweDevsOfficial:developfrom
sapayth:feature/account_page_elementor_widget

Conversation

@sapayth
Copy link
Member

@sapayth sapayth commented Mar 6, 2026

closes #1411

Summary

This PR adds a new Elementor widget for the WPUF Account page, allowing site builders to embed and customize the user account dashboard directly within the Elementor editor.

Technical Notes

  • Introduced Account_Widget and base Widget Elementor classes under WeDevs\Wpuf\Integrations\Elementor with full style controls (typography, colors, spacing, borders).
  • Added Elementor integration bootstrap in Integrations.php via elementor/init hook.
  • New filter wpuf_elementor_styles_to_enqueue allows customizing which styles load in the Elementor context.
  • Removed the React-based subscriptions admin UI (components, stores, build artifacts, and related npm/webpack config) in favor of the existing PHP implementation.
  • Subscription billing period display now uses the actual $recurring_des value instead of a hardcoded "/year" string.

Summary by CodeRabbit

Release Notes

  • New Features

    • Full Elementor integration with dedicated widgets for displaying WPUF forms and user account dashboards directly within page builders
    • Enhanced account template customization through extensible filters
  • Bug Fixes

    • Corrected HTML structure in dashboard templates
    • Improved icon and button styling for consistency
  • Improvements

    • Optimized template rendering for better compatibility with page builders

sapayth added 3 commits March 5, 2026 11:15
make UX better by removing common settings between container and Advance tab
@coderabbitai
Copy link

coderabbitai bot commented Mar 6, 2026

Walkthrough

This PR introduces comprehensive Elementor integration for WPUF, adding two new widget classes for displaying forms and account dashboards, registering an Elementor integration module, updating frontend initialization to support Elementor contexts, and refining account template rendering with filter hooks for template argument customization.

Changes

Cohort / File(s) Summary
Elementor Integration Core
includes/Integrations.php, includes/Integrations/Elementor/Elementor.php
Registers Elementor initialization hook and implements Elementor integration class with style/script enqueueing, category registration, widget registration, and form asset loading.
Elementor Widgets
includes/Integrations/Elementor/Widget.php, includes/Integrations/Elementor/Account_Widget.php
Adds two Elementor widget classes: Widget for rendering WPUF forms and Account_Widget for rendering the account dashboard, each with comprehensive style controls and lifecycle methods.
Account Template & Styling
templates/account.php, src/css/frontend/account.css, templates/dashboard/posts.php
Updates account template with SVG color changes, refactored link generation, alternative PHP syntax for control flow; removes border-radius Tailwind class from logout link; adds missing closing tags in dashboard posts template.
Core Frontend Updates
includes/Frontend/Frontend_Account.php, wpuf.php
Adds filter hook for account template argument customization; implements Elementor context detection to initialize Frontend in Elementor editor and AJAX scenarios.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related issues

  • weDevsOfficial/wpuf-pro#705: Directly implements requested Elementor widget support by adding complete integration module with form and account dashboard widgets.

Possibly related PRs

Suggested labels

needs: dev review

Poem

🐰 Widgets dance where Elementor plays,
Forms and accounts in stylish ways,
Filters bloom for customization's grace,
WPUF finds its rightful place!

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The PR addresses Elementor account widget functionality, but the linked issue #1411 concerns reCAPTCHA V2 login errors—a different scope not reflected in the changeset. Either address the reCAPTCHA V2 login error from issue #1411 in this PR, or unlink #1411 and link issues that correspond to the Elementor widget feature.
Out of Scope Changes check ⚠️ Warning The PR includes substantial out-of-scope changes unrelated to Elementor widget development: CSS modifications, template refactoring, and account page filter additions. Isolate Elementor integration changes into a focused PR. Move account page CSS/template modifications and filter additions to a separate maintenance or refactoring PR.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'feature: account page elementor widget' accurately describes the main change: adding an Elementor widget for the account page.
Docstring Coverage ✅ Passed Docstring coverage is 95.35% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 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: 2

🧹 Nitpick comments (5)
includes/Integrations/Elementor/Elementor.php (2)

83-97: Redundant function existence check.

The check if ( function_exists( 'wp_enqueue_script' ) ) on line 87 is unnecessary since wp_enqueue_script is a core WordPress function that is always available at this stage of the request lifecycle.

♻️ Suggested simplification
         if ( function_exists( 'wp_enqueue_editor' ) ) {
             wp_enqueue_editor();
             
             // Also explicitly enqueue TinyMCE scripts if available
-            if ( function_exists( 'wp_enqueue_script' ) ) {
-                // Check if these scripts exist and enqueue them
-                global $wp_scripts;
-                if ( isset( $wp_scripts->registered['tinymce'] ) ) {
-                    wp_enqueue_script( 'tinymce' );
-                }
-                if ( isset( $wp_scripts->registered['wp-tinymce'] ) ) {
-                    wp_enqueue_script( 'wp-tinymce' );
-                }
+            global $wp_scripts;
+            if ( isset( $wp_scripts->registered['tinymce'] ) ) {
+                wp_enqueue_script( 'tinymce' );
+            }
+            if ( isset( $wp_scripts->registered['wp-tinymce'] ) ) {
+                wp_enqueue_script( 'wp-tinymce' );
             }
         }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@includes/Integrations/Elementor/Elementor.php` around lines 83 - 97, Remove
the redundant function_exists check for wp_enqueue_script and simplify the
block: after calling wp_enqueue_editor() keep the global $wp_scripts and
directly check isset($wp_scripts->registered['tinymce']) and
isset($wp_scripts->registered['wp-tinymce']) and call
wp_enqueue_script('tinymce') and wp_enqueue_script('wp-tinymce') as needed;
reference wp_enqueue_editor, wp_enqueue_script, $wp_scripts, 'tinymce' and
'wp-tinymce' to locate the code to change.

55-58: Scripts enqueued in a styles callback may not be registered yet.

Enqueueing scripts (wpuf-conditional-logic, wpuf-frontend-form) inside enqueue_styles() which is hooked to elementor/frontend/after_enqueue_styles could fail if these scripts aren't yet registered at that point. Also, wpuf-frontend-form is enqueued again unconditionally in enqueue_wpuf_form_assets() (line 126), causing redundancy.

♻️ Suggested improvement

Move the Pro script enqueue logic to enqueue_scripts() where other scripts are handled:

     public function enqueue_styles() {
         // ... style dequeuing and enqueueing ...
-
-        if ( wpuf_is_pro_active() ) {
-            wp_enqueue_script( 'wpuf-conditional-logic' );
-            wp_enqueue_script( 'wpuf-frontend-form' );
-        }
-
         /**
          * Fires after WPUF has enqueued its styles in Elementor context.

Then in enqueue_scripts():

     public function enqueue_scripts() {
         // Enqueue all required WPUF form assets
         $this->enqueue_wpuf_form_assets();
+
+        // Conditionally enqueue Pro scripts
+        if ( wpuf_is_pro_active() ) {
+            wp_enqueue_script( 'wpuf-conditional-logic' );
+        }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@includes/Integrations/Elementor/Elementor.php` around lines 55 - 58, Move the
Pro script enqueue logic out of enqueue_styles() and into enqueue_scripts() so
scripts are enqueued at the proper hook; specifically, remove the
wp_enqueue_script('wpuf-conditional-logic') and
wp_enqueue_script('wpuf-frontend-form') calls from enqueue_styles() and add them
under the wpuf_is_pro_active() check inside enqueue_scripts() instead, ensuring
you keep the wpuf_is_pro_active() guard and avoid double-enqueue with
enqueue_wpuf_form_assets() by deleting the unconditional wpuf-frontend-form
enqueue in enqueue_wpuf_form_assets() or by checking is_script_enqueued before
adding it.
includes/Integrations/Elementor/Widget.php (3)

1116-1117: Using wp_kses_post() on render attribute string is unconventional.

Elementor's get_render_attribute_string() already returns properly escaped attribute strings. Wrapping it with wp_kses_post() (which is designed for post content) is redundant and could theoretically strip valid attribute values in edge cases.

Consider using the standard Elementor pattern
-        echo '<div ' . wp_kses_post( $this->get_render_attribute_string( 'wrapper' ) ) . '>';
+        ?>
+        <div <?php $this->print_render_attribute_string( 'wrapper' ); ?>>
+        <?php
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@includes/Integrations/Elementor/Widget.php` around lines 1116 - 1117, The
render attribute string is being double-escaped by wrapping Elementor's
get_render_attribute_string('wrapper') with wp_kses_post; remove wp_kses_post
and output the attribute string directly so Elementor's own escaping is
preserved. Update the echo line that builds the wrapper (where
get_render_attribute_string and 'wrapper' are used) to use
$this->get_render_attribute_string('wrapper') without wp_kses_post, keeping the
existing echo $output comment and phpcs ignore as-is.

1067-1067: Sanitize form_id before use in shortcode.

The form_id value should be cast to an integer before being used in the shortcode string. While the value comes from a SELECT control with predefined options, defensive coding ensures robustness against unexpected input.

Proposed fix
-        $form_id  = isset( $settings['form_id'] ) ? $settings['form_id'] : null;
+        $form_id  = isset( $settings['form_id'] ) ? absint( $settings['form_id'] ) : 0;

-        if ( empty( $form_id ) ) {
+        if ( ! $form_id ) {
             return;
         }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@includes/Integrations/Elementor/Widget.php` at line 1067, The $form_id pulled
from settings is not sanitized; update the assignment in the Widget class so
$form_id is cast to an integer (e.g., via (int) or intval) when reading
$settings['form_id'] and use that sanitized integer in the shortcode
construction/usage (references: the $form_id variable and the shortcode
invocation where it is embedded) to ensure only an integer is passed to the
shortcode.

1126-1141: Global error handler override may mask legitimate errors.

Overriding window.onerror to suppress specific errors during Elementor preview could inadvertently hide real issues during development. While the handler is restored after 2 seconds, this window may not be sufficient for slower environments, and it could interfere with other error monitoring tools.

Consider a more targeted approach, such as wrapping specific initialization calls in try-catch blocks instead of globally intercepting all errors.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@includes/Integrations/Elementor/Widget.php` around lines 1126 - 1141, The
global override of window.onerror (and the originalErrorHandler assignment) can
mask real errors; remove the temporary window.onerror override and instead wrap
the specific third-party initialization calls that trigger "google is not
defined" or "barrating is not a function" in targeted try-catch blocks (or check
for the existence of google/barrating before calling) inside the Elementor
preview initialization code (the same area where window.onerror was set); if you
must log/suppress only those messages, catch the exceptions locally and
handle/log them there rather than replacing window.onerror, and ensure any
original error handler is left untouched (do not modify
originalErrorHandler/window.onerror globally).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@includes/Integrations/Elementor/Elementor.php`:
- Line 40: Update the used style handle to the registered one: replace
occurrences of 'wpuf-elementor-frontend-forms' with the existing registered
handle 'wpuf-frontend-forms' (in includes/Integrations/Elementor/Elementor.php
where $style_handles is defined and in Widget.php where the non-existent handle
is referenced, e.g., the enqueue call or any variable referencing that handle)
so wp_enqueue_style() uses a registered style handle and styles load in
Elementor context.

In `@includes/Integrations/Elementor/Widget.php`:
- Around line 1143-1145: The DOM selector for TinyMCE is not scoped and uses
document.querySelector('.wpuf-elementor-widget-wrapper') which picks only the
first widget; update the widget rendering to output a unique wrapper identifier
(e.g. in the render method set a unique_id like 'wpuf-widget-' + $this->get_id()
via add_render_attribute('wrapper', 'id', $unique_id')) and change the JS that
sets wrapper (the variable named wrapper in the script that currently calls
document.querySelector) to select by that unique id (or scope via the script
element context) so each instance targets its own textarea.wp-editor-area
elements; ensure references include the same unique_id used in render and the
wrapper variable in the JS.

---

Nitpick comments:
In `@includes/Integrations/Elementor/Elementor.php`:
- Around line 83-97: Remove the redundant function_exists check for
wp_enqueue_script and simplify the block: after calling wp_enqueue_editor() keep
the global $wp_scripts and directly check
isset($wp_scripts->registered['tinymce']) and
isset($wp_scripts->registered['wp-tinymce']) and call
wp_enqueue_script('tinymce') and wp_enqueue_script('wp-tinymce') as needed;
reference wp_enqueue_editor, wp_enqueue_script, $wp_scripts, 'tinymce' and
'wp-tinymce' to locate the code to change.
- Around line 55-58: Move the Pro script enqueue logic out of enqueue_styles()
and into enqueue_scripts() so scripts are enqueued at the proper hook;
specifically, remove the wp_enqueue_script('wpuf-conditional-logic') and
wp_enqueue_script('wpuf-frontend-form') calls from enqueue_styles() and add them
under the wpuf_is_pro_active() check inside enqueue_scripts() instead, ensuring
you keep the wpuf_is_pro_active() guard and avoid double-enqueue with
enqueue_wpuf_form_assets() by deleting the unconditional wpuf-frontend-form
enqueue in enqueue_wpuf_form_assets() or by checking is_script_enqueued before
adding it.

In `@includes/Integrations/Elementor/Widget.php`:
- Around line 1116-1117: The render attribute string is being double-escaped by
wrapping Elementor's get_render_attribute_string('wrapper') with wp_kses_post;
remove wp_kses_post and output the attribute string directly so Elementor's own
escaping is preserved. Update the echo line that builds the wrapper (where
get_render_attribute_string and 'wrapper' are used) to use
$this->get_render_attribute_string('wrapper') without wp_kses_post, keeping the
existing echo $output comment and phpcs ignore as-is.
- Line 1067: The $form_id pulled from settings is not sanitized; update the
assignment in the Widget class so $form_id is cast to an integer (e.g., via
(int) or intval) when reading $settings['form_id'] and use that sanitized
integer in the shortcode construction/usage (references: the $form_id variable
and the shortcode invocation where it is embedded) to ensure only an integer is
passed to the shortcode.
- Around line 1126-1141: The global override of window.onerror (and the
originalErrorHandler assignment) can mask real errors; remove the temporary
window.onerror override and instead wrap the specific third-party initialization
calls that trigger "google is not defined" or "barrating is not a function" in
targeted try-catch blocks (or check for the existence of google/barrating before
calling) inside the Elementor preview initialization code (the same area where
window.onerror was set); if you must log/suppress only those messages, catch the
exceptions locally and handle/log them there rather than replacing
window.onerror, and ensure any original error handler is left untouched (do not
modify originalErrorHandler/window.onerror globally).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e5231e67-865a-427f-b1c9-3e74ed19564f

📥 Commits

Reviewing files that changed from the base of the PR and between 5f313fa and 541b9f4.

📒 Files selected for processing (9)
  • includes/Frontend/Frontend_Account.php
  • includes/Integrations.php
  • includes/Integrations/Elementor/Account_Widget.php
  • includes/Integrations/Elementor/Elementor.php
  • includes/Integrations/Elementor/Widget.php
  • src/css/frontend/account.css
  • templates/account.php
  • templates/dashboard/posts.php
  • wpuf.php

wp_dequeue_style('wpuf-layout4');
wp_dequeue_style('wpuf-layout5');

$style_handles = [ 'wpuf-elementor-frontend-forms', 'wpuf-account' ];
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

🏁 Script executed:

# Search for style registrations containing 'elementor-frontend-forms'
rg -n "elementor-frontend-forms" --type=php

# Check all registered styles in Assets.php
rg -n "wp_register_style" includes/Assets.php -A 3

# Show the context around line 40 in Elementor.php
cat -n includes/Integrations/Elementor/Elementor.php | head -80

Repository: weDevsOfficial/wp-user-frontend

Length of output: 3606


🏁 Script executed:

# Search for the styles array definition in Assets.php
rg -n "get_styles|'elementor-frontend-forms'|\"elementor-frontend-forms\"" includes/Assets.php -B 2 -A 50 | head -150

# Also search for 'frontend-forms' to see what styles are actually registered
rg -n "'frontend-forms'|\"frontend-forms\"" includes/Assets.php -B 2 -A 2

Repository: weDevsOfficial/wp-user-frontend

Length of output: 4546


🏁 Script executed:

# Continue viewing the rest of get_styles() method to find 'account' and 'elementor-frontend-forms'
rg -n "get_styles" -A 200 includes/Assets.php | grep -E "(account|elementor-frontend-forms|'[a-z-]+'.*=>)"

Repository: weDevsOfficial/wp-user-frontend

Length of output: 6327


Missing style handle: wpuf-elementor-frontend-forms is not registered.

The style handle wpuf-elementor-frontend-forms used in line 40 (and referenced in Widget.php:75) is not registered in includes/Assets.php. The available style handles are wpuf-frontend-forms, wpuf-account, and others. This will cause wp_enqueue_style() to fail silently and styles won't load in Elementor context.

Proposed fix

Use the existing wpuf-frontend-forms handle:

-        $style_handles = [ 'wpuf-elementor-frontend-forms', 'wpuf-account' ];
+        $style_handles = [ 'wpuf-frontend-forms', 'wpuf-account' ];

Also update Widget.php:75 if it references the non-existent handle.

📝 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
$style_handles = [ 'wpuf-elementor-frontend-forms', 'wpuf-account' ];
$style_handles = [ 'wpuf-frontend-forms', 'wpuf-account' ];
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@includes/Integrations/Elementor/Elementor.php` at line 40, Update the used
style handle to the registered one: replace occurrences of
'wpuf-elementor-frontend-forms' with the existing registered handle
'wpuf-frontend-forms' (in includes/Integrations/Elementor/Elementor.php where
$style_handles is defined and in Widget.php where the non-existent handle is
referenced, e.g., the enqueue call or any variable referencing that handle) so
wp_enqueue_style() uses a registered style handle and styles load in Elementor
context.

Comment on lines +1143 to +1145
var wrapper = document.querySelector('.wpuf-elementor-widget-wrapper');
if (wrapper) {
var textareas = wrapper.querySelectorAll('textarea.wp-editor-area');
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

DOM selector is not scoped to current widget instance.

Using document.querySelector('.wpuf-elementor-widget-wrapper') will only select the first matching element on the page. If multiple WPUF form widgets are added to the same page, the TinyMCE initialization will only target the first widget's textareas, leaving others uninitialized.

Consider scoping the selector to the current widget's wrapper element.

Proposed fix using script element context
-                var wrapper = document.querySelector('.wpuf-elementor-widget-wrapper');
+                // Get wrapper relative to this script's position
+                var scripts = document.querySelectorAll('script');
+                var currentScript = scripts[scripts.length - 1];
+                var wrapper = currentScript.previousElementSibling;
+                while (wrapper && !wrapper.classList.contains('wpuf-elementor-widget-wrapper')) {
+                    wrapper = wrapper.previousElementSibling;
+                }

Alternatively, you could output a unique ID for each widget instance:

// In the render method, before the script:
$unique_id = 'wpuf-widget-' . $this->get_id();
$this->add_render_attribute( 'wrapper', 'id', $unique_id );

Then in the JavaScript:

var wrapper = document.getElementById('<?php echo esc_js( $unique_id ); ?>');
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@includes/Integrations/Elementor/Widget.php` around lines 1143 - 1145, The DOM
selector for TinyMCE is not scoped and uses
document.querySelector('.wpuf-elementor-widget-wrapper') which picks only the
first widget; update the widget rendering to output a unique wrapper identifier
(e.g. in the render method set a unique_id like 'wpuf-widget-' + $this->get_id()
via add_render_attribute('wrapper', 'id', $unique_id')) and change the JS that
sets wrapper (the variable named wrapper in the script that currently calls
document.querySelector) to select by that unique id (or scope via the script
element context) so each instance targets its own textarea.wp-editor-area
elements; ensure references include the same unique_id used in render and the
wrapper variable in the JS.

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