Skip to content

Feature/post form gutenberg block#1850

Open
sapayth wants to merge 4 commits into
weDevsOfficial:developfrom
sapayth:feature/post_form_gutenberg_block
Open

Feature/post form gutenberg block#1850
sapayth wants to merge 4 commits into
weDevsOfficial:developfrom
sapayth:feature/post_form_gutenberg_block

Conversation

@sapayth
Copy link
Copy Markdown
Contributor

@sapayth sapayth commented Apr 24, 2026

closes #811
closes #1496
closes #1497
closes #1498
closes #1499

Summary

Rebuilds the WPUF Gutenberg block for post forms with a proper design panel — site builders can now control typography, colors, spacing, and borders for each inserted form directly from the block editor, without touching CSS. Styles are scoped per block instance, so two forms on the same page can look different.

Technical Notes

  • New block ID: wpuf/post-form (replaces the legacy wpuf/wpuf-form-block). Existing posts using the old block will show a block-recovery prompt in the editor.
  • Rendering still goes through the [wpuf_form] shortcode (includes/templates/blocks/post-form.php) — no change to shortcode output, hooks, or filters.
  • Block registration moved to includes/Blocks/PostForm.php; the legacy class WeDevs\Wpuf\Frontend\Form_Gutenberg_Block has been removed along with its asset bundle (assets/js/admin/gutenblock.js, assets/css/admin/gutenblock.css, assets/js/admin/blockFrameSetup.js).
  • Multi-step forms now render in the editor preview (REST preview bypasses form gating — see includes/templates/blocks/post-form.php:18).
  • Build: new block source under src/js/blocks/post-form/; webpack config updated (webpack.config.js).

Breaking Changes

  • Legacy block instances: posts/pages that previously used the old Gutenberg form block will need to be re-inserted with the new block. The shortcode ([wpuf_form id="…"]) continues to work unchanged as a fallback.
  • Removed public class: WeDevs\Wpuf\Frontend\Form_Gutenberg_Block is no longer loaded. Any custom code referencing it should switch to WeDevs\Wpuf\Blocks\PostForm or the shortcode.

Summary by CodeRabbit

  • New Features

    • Post Form block for Gutenberg editor featuring multiple design templates and comprehensive styling controls for labels, fields, buttons, and progress indicators
  • Improvements

    • Improved form field spacing for radio and checkbox inputs
    • Optimized form styling and layout
  • Deprecations

    • Legacy Form Gutenberg block removed

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 24, 2026

Warning

Rate limit exceeded

@sapayth has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 35 minutes and 28 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 35 minutes and 28 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 3f45f51b-9fed-4f8e-8a7a-63b264de3a03

📥 Commits

Reviewing files that changed from the base of the PR and between 0729000 and 59f5508.

⛔ Files ignored due to path filters (6)
  • assets/js/account.min.js is excluded by !**/*.min.js
  • assets/js/ai-form-builder.min.js is excluded by !**/*.min.js
  • assets/js/forms-list.min.js is excluded by !**/*.min.js
  • assets/js/frontend-subscriptions.min.js is excluded by !**/*.min.js
  • assets/js/subscriptions.min.js is excluded by !**/*.min.js
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (10)
  • assets/css/admin/form-builder.css
  • assets/css/admin/subscriptions.min.css
  • assets/css/ai-form-builder.css
  • assets/css/ai-form-builder.min.css
  • assets/css/forms-list.min.css
  • assets/css/frontend-subscriptions.min.css
  • assets/css/frontend/account.css
  • includes/Admin.php
  • package.json
  • wpuf.php

Walkthrough

This pull request replaces the legacy Gutenberg form block system with a new, more comprehensive "post-form" block featuring an enhanced editor UI, template selection system, and extensible styling options. The old block integration is removed entirely and replaced with a new dedicated block class, React component architecture, and webpack-based build system.

Changes

Cohort / File(s) Summary
Old Block System Removal
assets/css/admin/gutenblock.css, assets/js/admin/gutenblock.js, assets/js/admin/blockFrameSetup.js, includes/Frontend/Form_Gutenberg_Block.php
Deleted legacy Gutenberg form block implementation including editor styles, JavaScript registration, iframe setup logic, and form preview frame handler (total ~340 lines removed).
New Post-Form Block Core
includes/Blocks/PostForm.php, includes/templates/blocks/post-form.php
Added new PostForm block class with block registration, asset localization, and comprehensive template rendering with support for styling customization, multistep forms, and label position variants (~890 lines).
Post-Form Block Editor UI
src/js/blocks/post-form/edit.js, src/js/blocks/post-form/templates.js, src/js/blocks/post-form/index.js, src/js/blocks/post-form/save.js
Created React-based block editor with form selection, template picker, style inspector panels, server-side render preview, and five template presets with predefined styling configurations (~1200 lines).
Post-Form Block Configuration
src/js/blocks/post-form/block.json, assets/js/blocks/js/blocks/post-form/block.json, webpack.config.js, assets/js/blocks/post-form.asset.php
Added block metadata definitions, webpack build configuration for block compilation, and asset manifest files to support the new block build pipeline.
Post-Form Block Styling
src/js/blocks/post-form/editor.css, assets/js/blocks/post-form-rtl.css, assets/js/blocks/post-form.css
Added editor and frontend CSS stylesheets defining template picker grid layout, form preview components, loading overlays, and spinner animations (~450 lines total).
Frontend Form Layout Updates
assets/css/frontend-form/layout2.css, assets/css/frontend-form/layout4.css, assets/less/frontend-forms.less, assets/css/frontend-forms.css
Refined form input and radio/checkbox styling: restricted error/interactive styles to text-like inputs, converted radio/checkbox blocks to flexbox layout, removed file selector icon pseudo-element, and adjusted spacing/alignment (~30 lines net change).
Plugin Infrastructure Changes
includes/Admin.php, includes/Frontend.php, wpuf.php, package.json
Updated service container to register new PostForm block instead of legacy block, added wpuf/post-form block detection to script enqueue logic, and extended npm build pipeline with block build scripts and @wordpress/scripts dependency.
Debug Code Removal
includes/Integrations/Events_Calendar/Compatibility/TEC_V6_Compatibility.php
Removed conditional debug logging statements from TEC compatibility layer (no functional impact).

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Suggested labels

needs: dev review

Poem

🐰 A new form block hops into view,
With templates and styling fresh and true,
The old frame has gone its way,
Webpack builds blocks today!
React editors make styling play!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The PR objectives state it replaces the legacy Gutenberg form block with a new 'wpuf/post-form' block, but linked issue #811 requires resolving a WooCommerce Bookings + Product Addons compatibility conflict—a completely unrelated problem. Address the WooCommerce compatibility issue (#811) separately or clarify the correct linked issue for this Gutenberg block replacement PR.
✅ 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 'Feature/post form gutenberg block' accurately describes the main change: a new Gutenberg block for post forms replaces the legacy form block.
Out of Scope Changes check ✅ Passed All changes are directly related to building the new 'wpuf/post-form' Gutenberg block, removing legacy block assets, and updating build configuration; no unrelated modifications are present.
Docstring Coverage ✅ Passed Docstring coverage is 85.00% 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

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
Copy Markdown

@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: 12

Caution

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

⚠️ Outside diff range comments (1)
assets/less/frontend-forms.less (1)

1291-1298: ⚠️ Potential issue | 🟡 Minor

Compiled CSS appears stale — regenerate frontend-forms.css.

The AI summary states the text-shadow on .wpuf-progress-percentage was removed here, and indeed this source block no longer contains it. However, assets/css/frontend-forms.css (lines 1153–1160) still emits text-shadow: 1px 1px 0 #fff; for the same selector. The compiled CSS is out of sync with the LESS source — re-run the build (grunt less / equivalent) and commit the refreshed frontend-forms.css so users actually get the style change.

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

In `@assets/less/frontend-forms.less` around lines 1291 - 1298, The compiled
stylesheet is out of sync with the LESS source: the .wpuf-progress-percentage
selector no longer has text-shadow in the LESS but the generated
frontend-forms.css still does; re-run the LESS build (e.g., grunt less or your
project's build task) to regenerate frontend-forms.css, verify the
.wpuf-progress-percentage rule no longer includes text-shadow, and commit the
updated compiled stylesheet so the runtime CSS matches the LESS source.
🧹 Nitpick comments (7)
assets/css/frontend-form/layout2.css (3)

37-52: Avoid !important on width: 100%.

The previous shared rule used plain width: 100% without !important. Since the selector now already excludes file/radio/checkbox/submit via :not(), there's no internal rule left for !important to win against inside this layout — it only makes it harder for site builders and the new per-block design panel (PR objective) to override widths via higher-specificity styles. Consider dropping !important unless there's a specific third-party/dashboard rule you're trying to defeat (if so, please document it in a comment).

♻️ Proposed diff
 .wpuf-form-add.wpuf-form-layout2 ul.wpuf-form li .wpuf-fields input:not([type="file"]):not([type="radio"]):not([type="checkbox"]):not([type="submit"]),
 .wpuf-form-add.wpuf-form-layout2 ul.wpuf-form li .wpuf-fields textarea {
-  width: 100% !important;
+  width: 100%;
   background: `#292C3F`;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@assets/css/frontend-form/layout2.css` around lines 37 - 52, Remove the
unnecessary "!important" on the width rule in the selector
".wpuf-form-add.wpuf-form-layout2 ul.wpuf-form li .wpuf-fields
input:not([type="file"]):not([type="radio"]):not([type="checkbox"]):not([type="submit"]),
.wpuf-form-add.wpuf-form-layout2 ul.wpuf-form li .wpuf-fields textarea" so that
"width: 100%" is overridable by higher-specificity or later rules (e.g., block
design panel); simply delete "!important" and, if you intentionally need to
override a third-party rule, add a comment explaining why and reference that
external source instead of using !important.

202-220: Interactive-state selector exclusions look correct.

Adding :not(.file-selector):not(.wpuf-insert-image) on the anchor and :not([type="file"]):not([type="radio"]):not([type="checkbox"]):not([type="submit"]) on input correctly prevents the green #00C14B focus/hover outline from hijacking the styled upload button (a.file-selector) and the image-insert anchor, both of which have their own distinct styling earlier in this file. Good targeted fix.

One small caveat: the selector list still contains textarea:visited / select:visited / input:visited pseudo-classes, which never apply to form controls (only to <a>). They were there before this PR, so not a blocker, but worth cleaning up while you're in this area.

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

In `@assets/css/frontend-form/layout2.css` around lines 202 - 220, The selector
list includes pseudo-class variants like textarea:visited, select:visited, and
input:not(...):visited which never apply to form controls; remove the :visited
occurrences from the grouped rules (target the active/hover/focus states only
for input, textarea, select and the anchor variants) so the ruleset only uses
:active, :hover, and :focus for .wpuf-form-add.wpuf-form-layout2 ul.wpuf-form li
input, textarea, select and the a:not(.file-selector):not(.wpuf-insert-image)
selectors.

53-65: Select block duplicates input/textarea styles — consider consolidating.

All the properties added to the select rule (background, box-shadow resets, border, border-radius, font-size, box-sizing, color) are identical to those applied to the input/textarea rule immediately above. Because the previous combined selector was split to drop select, you now maintain two copies of the same declaration block. A cleaner approach is to keep select in the shared selector for the common declarations and only override the specific select-only bits (padding, height) in a separate, smaller rule — same pattern used elsewhere in the file.

♻️ Suggested consolidation
-.wpuf-form-add.wpuf-form-layout2 ul.wpuf-form li .wpuf-fields input:not([type="file"]):not([type="radio"]):not([type="checkbox"]):not([type="submit"]),
-.wpuf-form-add.wpuf-form-layout2 ul.wpuf-form li .wpuf-fields textarea {
-  width: 100% !important;
+.wpuf-form-add.wpuf-form-layout2 ul.wpuf-form li .wpuf-fields input:not([type="file"]):not([type="radio"]):not([type="checkbox"]):not([type="submit"]),
+.wpuf-form-add.wpuf-form-layout2 ul.wpuf-form li .wpuf-fields textarea,
+.wpuf-form-add.wpuf-form-layout2 ul.wpuf-form li .wpuf-fields select {
+  width: 100%;
   background: `#292C3F`;
   -moz-box-shadow: none;
   -webkit-box-shadow: none;
   box-shadow: none;
-  border: 0;
-  font-size: 14px;
   border: 1px solid `#33374D`;
   border-radius: 5px;
-  padding: 10px 0 10px 10px;
+  font-size: 14px;
   box-sizing: border-box;
-  position: relative;
   color: `#fff`;
 }
+.wpuf-form-add.wpuf-form-layout2 ul.wpuf-form li .wpuf-fields input:not([type="file"]):not([type="radio"]):not([type="checkbox"]):not([type="submit"]),
+.wpuf-form-add.wpuf-form-layout2 ul.wpuf-form li .wpuf-fields textarea {
+  padding: 10px 0 10px 10px;
+  position: relative;
+}
 .wpuf-form-add.wpuf-form-layout2 ul.wpuf-form li .wpuf-fields select {
-  background: `#292C3F`;
-  -moz-box-shadow: none;
-  -webkit-box-shadow: none;
-  box-shadow: none;
-  border: 1px solid `#33374D`;
-  border-radius: 5px;
-  font-size: 14px;
-  box-sizing: border-box;
-  color: `#fff`;
   padding: 10px;
   height: inherit;
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@assets/css/frontend-form/layout2.css` around lines 53 - 65, The select rule
.wpuf-form-add.wpuf-form-layout2 ul.wpuf-form li .wpuf-fields select duplicates
many declarations already applied to the input/textarea rule above; consolidate
by re-adding select to the shared selector that defines background, box-shadow,
border, border-radius, font-size, box-sizing and color, then keep a small
separate selector (the existing .wpuf-form-add.wpuf-form-layout2 ul.wpuf-form li
.wpuf-fields select) only to override select-specific properties like padding
and height; this removes the duplicated declaration block and preserves the
select-only overrides.
includes/templates/blocks/post-form.php (1)

113-156: Extensive use of !important will make theme/user overrides painful.

Every button background, text color, box-shadow, text-shadow uses !important, plus upload button variants. Since these rules are already ID-scoped via #$block_id, they already beat class-based theme selectors without the nuclear option. The only legitimate !important here is when fighting specific theme rules that themselves use !important. Consider dropping !important from properties that don't demonstrably collide with common theme CSS; otherwise users who add a custom CSS block inside the page editor can't tweak anything.

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

In `@includes/templates/blocks/post-form.php` around lines 113 - 156, The CSS
arrays for selectors like "{$scope} .wpuf-form input[type='submit'], {$scope}
.wpuf-form button[type='submit']" and "{$scope} .wpuf-form a.file-selector" are
appending " !important" to properties (background-color, color, box-shadow,
text-shadow and upload button fallbacks), which prevents user/theme overrides;
remove the hardcoded " !important" suffixes for values derived from
$block_config keys (button_background_color, button_text_color,
upload_btn_background_color, upload_btn_text_color) and for the 'box-shadow' and
'text-shadow' entries so the scoped ID selector suffices, and if a true override
is ever needed implement it conditionally (e.g. via a new $block_config flag
like force_important) rather than always concatenating "!important".
src/js/blocks/post-form/edit.js (1)

814-822: console.warn/console.error invoked during render.

Calling console.warn directly in the body of EmptyResponsePlaceholder and ErrorResponsePlaceholder means every render of these placeholders — including React's StrictMode double-invocations in development and any re-renders triggered by unrelated state changes — produces a new log line. Move the logs into a useEffect so they fire once per mount (or once per response change):

♻️ Log side-effects in `useEffect`
-                            EmptyResponsePlaceholder={() => {
-                                // eslint-disable-next-line no-console
-                                console.warn( '[WPUF PostForm] SSR returned empty response', { formId } );
-                                return (
+                            EmptyResponsePlaceholder={() => {
+                                useEffect(() => {
+                                    // eslint-disable-next-line no-console
+                                    console.warn( '[WPUF PostForm] SSR returned empty response', { formId } );
+                                }, []);
+                                return (
                                     <p style={{ padding: '12px', background: '#fff3cd', border: '1px solid `#ffeeba`' }}>
                                         { __( 'SSR returned an empty response. Check the PHP error log.', 'wp-user-frontend' ) }
                                     </p>
                                 );
                             }}
                             ErrorResponsePlaceholder={({ response }) => {
-                                // eslint-disable-next-line no-console
-                                console.error( '[WPUF PostForm] SSR error response', response );
+                                useEffect(() => {
+                                    // eslint-disable-next-line no-console
+                                    console.error( '[WPUF PostForm] SSR error response', response );
+                                }, [response]);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/js/blocks/post-form/edit.js` around lines 814 - 822,
EmptyResponsePlaceholder currently calls console.warn inside its render body
(and similarly ErrorResponsePlaceholder elsewhere), causing repeated logs on
every render; update EmptyResponsePlaceholder and ErrorResponsePlaceholder so
their logging runs inside a useEffect hook that depends on formId or the
error/response state respectively, moving the console.warn/console.error calls
into the effect and leaving the JSX return unchanged so the log fires only once
per mount or when the relevant response changes.
webpack.config.js (1)

12-15: Merge output with defaultConfig to preserve webpack defaults.

The output config is completely replaced rather than merged with defaultConfig, discarding settings like chunkFilename that @wordpress/scripts 31.8.0 provides. While this block doesn't currently use code-splitting, merging ensures compatibility with defaults and prevents issues if the block evolves.

♻️ Merge with default output
-    output: {
-        path: path.resolve( __dirname, 'assets/js/blocks' ),
-        filename: '[name].js',
-    },
+    output: {
+        ...defaultConfig.output,
+        path: path.resolve( __dirname, 'assets/js/blocks' ),
+        filename: '[name].js',
+    },
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@webpack.config.js` around lines 12 - 15, The custom output object currently
replaces webpack's defaults and drops settings like chunkFilename; update the
export so the output is merged with defaultConfig.output (e.g., use spread or
Object.assign to combine defaultConfig.output and your output) so that
properties such as chunkFilename provided by `@wordpress/scripts` are preserved;
reference the output key and defaultConfig (and the chunkFilename property) when
making the merge.
includes/Blocks/PostForm.php (1)

417-423: Brittle id-stripping regex on get_block_wrapper_attributes().

The regex '/\s*id="[^"]*"/' only matches double-quoted id attributes. It will miss single-quoted output and is sensitive to future core changes in get_block_wrapper_attributes(). Also, core only emits id="..." when the block has an anchor attribute set, so in most cases this preg_replace is a no-op.

If the intent is just to avoid a duplicate id, consider emitting the scoping id on an inner wrapper in the template and leaving get_block_wrapper_attributes() output intact. If the strip is truly needed, at minimum make the pattern quote-agnostic.

♻️ Quote-agnostic pattern (if strip is kept)
-        $wrapper_attributes = preg_replace(
-            '/\s*id="[^"]*"/',
-            '',
-            get_block_wrapper_attributes( [ 'class' => 'wpuf-post-form-block' ] )
-        );
+        $wrapper_attributes = preg_replace(
+            '/\s*id=("[^"]*"|\'[^\']*\')/',
+            '',
+            get_block_wrapper_attributes( [ 'class' => 'wpuf-post-form-block' ] )
+        );
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@includes/Blocks/PostForm.php` around lines 417 - 423, The current
preg_replace that strips id from get_block_wrapper_attributes() is brittle (only
handles double quotes) and unnecessary in most cases; either remove this
stripping and emit your scoping id on an inner wrapper in the template (keep
get_block_wrapper_attributes( [ 'class' => 'wpuf-post-form-block' ] ) output
intact) or, if you truly must strip the id, replace the regex in the
$wrapper_attributes assignment with a quote-agnostic pattern that matches both
single and double quotes and is tolerant of spacing; refer to
get_block_wrapper_attributes() and the $wrapper_attributes variable to locate
the change and update the preg_replace accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@assets/js/blocks/js/blocks/post-form/block.json`:
- Line 1: The duplicated build artifact
assets/js/blocks/js/blocks/post-form/block.json is unused at runtime because
register_block_type() in includes/Blocks/PostForm.php points to WPUF_ROOT .
'/src/js/blocks/post-form', creating two divergent sources of truth; fix by
either updating register_block_type() to point to the built path (so the runtime
consumes the copied block.json) or stop the copy step in the build by
removing/excluding block.json from the CopyWebpackPlugin patterns in
webpack.config.js so only src/js/blocks/post-form/block.json remains; choose one
approach, update the corresponding path/config (register_block_type or
CopyWebpackPlugin) and remove the redundant file from the repository if
switching to the built-path option.

In `@assets/js/blocks/post-form.css`:
- Around line 1-152: The committed build artifact assets/js/blocks/post-form.css
has a trivial trailing newline drift compared to the source
src/js/blocks/post-form/editor.css (selectors like .wpuf-pf-templates,
.wpuf-pf-template-card, .wpuf-ssr-loading are present), so regenerate the CSS
from source and recommit the built file; update the local workflow/CI to run the
build step (e.g., npm/yarn script that produces post-form.css) before commits or
as a pre-merge check to prevent future drift, and add a simple file-consistency
check in CI to fail if generated assets differ from source-produced artifacts.

In `@includes/Blocks/PostForm.php`:
- Around line 57-92: register_block() currently registers editor scripts/styles
and calls get_editor_data() on every init (frontend/REST), causing unnecessary
DB queries; change it so register_block_type( ...) stays in register_block() on
init but move wp_register_script, wp_register_style and
wp_localize_script/get_editor_data() out of init and into an editor-only hook
(e.g., hook a new localize_editor_data() or enqueue_editor_assets() to
enqueue_block_editor_assets or at minimum is_admin()/rest checks) so the
get_editor_data() query only runs when the block editor loads; update references
to 'wpuf-post-form-editor' and 'wpufPostForm' inside the new editor hook and
ensure register_block_type still points to [ $this, 'render' ].

In `@includes/Frontend.php`:
- Line 58: The current Frontend.php check uses has_block('wpuf/post-form',
$post) and misses placements outside post_content; instead add a render-time
detector using the render_block (filter or action) to catch when the
wpuf/post-form block is rendered and enqueue the frontend asset handles
(wpuf-frontend-forms, wpuf-frontend-form) there; update or remove the
has_block-dependent path and implement a callback (e.g., on_render_block) that
checks the block name === 'wpuf/post-form' and calls
wp_enqueue_style/wp_enqueue_script so assets load for blocks rendered from
templates, template parts, reusable blocks, or widgets.

In `@includes/templates/blocks/post-form.php`:
- Around line 344-345: The connector line added to $steps_html uses a percentage
vertical offset ("top: 30%") which misaligns with the 34px circles; update the
inline style for that div (the connector line string appended to $steps_html) to
use a pixel-based top value equal to half the circle height (e.g. "top: 17px")
so the line is vertically centered on the circles regardless of wrapper/label
height.
- Around line 285-308: The code assembles CSS into $style_output by escaping
property names/values with esc_attr (inside the foreach over $css_rules), which
corrupts CSS and is not safe for style contexts; fix it by removing esc_attr()
for CSS token output, validate/normalize each $value with a CSS-safe sanitizer
or allow-list (e.g. a regex that strips disallowed characters or
wp_strip_all_tags plus a CSS-token check) in the loop that builds $declarations,
ensure property names ($prop) are matched against a whitelist of allowed CSS
properties, keep the SVG->data URL creation for $upload_icon_url but ensure it
is rawurlencode'd as before, and finally run a last-pass sanitizer like
wp_strip_all_tags() or a strict validator on $style_output before echoing in the
style tag to prevent injection.
- Around line 218-220: The meta-sourced color fallbacks
($form_settings_meta['ms_active_bgcolor'], ['ms_ac_txt_color'], ['ms_bgcolor'])
assigned to $ms_active_bg, $ms_active_txt and $ms_inactive are not sanitized for
CSS and can allow injection; update those assignments to pass the meta values
through WordPress's sanitize_hex_color() and if that returns empty/invalid, fall
back to the existing literal hex defaults (e.g. '#00a0d2', '#ffffff', '#e4e4e4')
so only valid hex colors reach the stylesheet before further escaping/output
(keep the same variable names $ms_active_bg, $ms_active_txt, $ms_inactive).
- Around line 416-420: The current preg_replace on $shortcode_output uses a
regex that assumes class is the first attribute on <button> (the pattern in the
preg_replace call), which fails when other attributes (type, id, data-*) appear
before class; update the regex used in the preg_replace call so it matches a
<button> element regardless of attribute order by searching for a class
attribute that contains "wpuf-multistep-(prev|next)-btn" anywhere among the tag
attributes, then inject the disabled attribute while preserving all existing
attributes and their order; modify only the pattern passed to preg_replace (the
$shortcode_output replacement logic) to be order-agnostic and case-insensitive
and ensure it still targets the same class fragment.

In `@src/js/blocks/post-form/edit.js`:
- Around line 254-271: The isUpdating flag can remain true if ServerSideRender
never mounts LoadingResponsePlaceholder; modify the logic so isUpdating is
cleared when the server render settles or when non-loading placeholders mount:
update the attributes useEffect (which uses isUpdating, setIsUpdating,
debounceTimerRef) to also clear/setIsUpdating(false) in the settled/error/empty
paths or add a separate effect tied to ServerSideRender's lifecycle (or to any
state/prop that indicates a settled response) that calls setIsUpdating(false);
ensure any debounceTimerRef timeouts are cleared and setIsUpdating(false) runs
on unmount so LoadingResponsePlaceholder's unmount is not the sole mechanism for
clearing isUpdating.
- Around line 276-311: handleTemplateSelect currently stores the undo snapshot
in the shared prevAttrsRef which gets overwritten by subsequent template
selections; change it to either (A) capture the snapshot in the createNotice
closure (e.g., const snapshot = { ...attributes } local to handleTemplateSelect
and reference that inside the notice's onClick) so each snackbar has its own
immutable snapshot, or (B) track the notice id returned from createNotice and
call removeNotice(previousNoticeId) before creating a new notice and also clear
prevAttrsRef when removing; update references to prevAttrsRef, createNotice,
removeNotice, setAttributes, and handleTemplateSelect accordingly so each Undo
restores the correct per-notice snapshot and no shared state is reused.
- Around line 4-11: The code imports useSettings from `@wordpress/block-editor`
which was added in WP 6.5; update the plugin to require WordPress 6.5 by
changing the readme.txt "Requires at least" header to 6.5, or replace
useSettings with the older useSetting hook and adjust call sites (where
useSettings is used in this file) to account for useSetting returning a single
value (not [value, setter])—update any destructuring or assignments that expect
a pair and ensure any setters are replaced with appropriate state management.

In `@src/js/blocks/post-form/templates.js`:
- Around line 4-347: TEMPLATES preset objects use plain string literals for
label and description (e.g., TEMPLATES[*].label and TEMPLATES[*].description) so
they aren’t localizable; update each preset in the TEMPLATES array to wrap those
string literals with the localization function __(..., 'wp-user-frontend') so
the TemplateCard UI in edit.js receives translatable strings (apply to all
presets: 'default','dark','colorful','minimal','bold').

---

Outside diff comments:
In `@assets/less/frontend-forms.less`:
- Around line 1291-1298: The compiled stylesheet is out of sync with the LESS
source: the .wpuf-progress-percentage selector no longer has text-shadow in the
LESS but the generated frontend-forms.css still does; re-run the LESS build
(e.g., grunt less or your project's build task) to regenerate
frontend-forms.css, verify the .wpuf-progress-percentage rule no longer includes
text-shadow, and commit the updated compiled stylesheet so the runtime CSS
matches the LESS source.

---

Nitpick comments:
In `@assets/css/frontend-form/layout2.css`:
- Around line 37-52: Remove the unnecessary "!important" on the width rule in
the selector ".wpuf-form-add.wpuf-form-layout2 ul.wpuf-form li .wpuf-fields
input:not([type="file"]):not([type="radio"]):not([type="checkbox"]):not([type="submit"]),
.wpuf-form-add.wpuf-form-layout2 ul.wpuf-form li .wpuf-fields textarea" so that
"width: 100%" is overridable by higher-specificity or later rules (e.g., block
design panel); simply delete "!important" and, if you intentionally need to
override a third-party rule, add a comment explaining why and reference that
external source instead of using !important.
- Around line 202-220: The selector list includes pseudo-class variants like
textarea:visited, select:visited, and input:not(...):visited which never apply
to form controls; remove the :visited occurrences from the grouped rules (target
the active/hover/focus states only for input, textarea, select and the anchor
variants) so the ruleset only uses :active, :hover, and :focus for
.wpuf-form-add.wpuf-form-layout2 ul.wpuf-form li input, textarea, select and the
a:not(.file-selector):not(.wpuf-insert-image) selectors.
- Around line 53-65: The select rule .wpuf-form-add.wpuf-form-layout2
ul.wpuf-form li .wpuf-fields select duplicates many declarations already applied
to the input/textarea rule above; consolidate by re-adding select to the shared
selector that defines background, box-shadow, border, border-radius, font-size,
box-sizing and color, then keep a small separate selector (the existing
.wpuf-form-add.wpuf-form-layout2 ul.wpuf-form li .wpuf-fields select) only to
override select-specific properties like padding and height; this removes the
duplicated declaration block and preserves the select-only overrides.

In `@includes/Blocks/PostForm.php`:
- Around line 417-423: The current preg_replace that strips id from
get_block_wrapper_attributes() is brittle (only handles double quotes) and
unnecessary in most cases; either remove this stripping and emit your scoping id
on an inner wrapper in the template (keep get_block_wrapper_attributes( [
'class' => 'wpuf-post-form-block' ] ) output intact) or, if you truly must strip
the id, replace the regex in the $wrapper_attributes assignment with a
quote-agnostic pattern that matches both single and double quotes and is
tolerant of spacing; refer to get_block_wrapper_attributes() and the
$wrapper_attributes variable to locate the change and update the preg_replace
accordingly.

In `@includes/templates/blocks/post-form.php`:
- Around line 113-156: The CSS arrays for selectors like "{$scope} .wpuf-form
input[type='submit'], {$scope} .wpuf-form button[type='submit']" and "{$scope}
.wpuf-form a.file-selector" are appending " !important" to properties
(background-color, color, box-shadow, text-shadow and upload button fallbacks),
which prevents user/theme overrides; remove the hardcoded " !important" suffixes
for values derived from $block_config keys (button_background_color,
button_text_color, upload_btn_background_color, upload_btn_text_color) and for
the 'box-shadow' and 'text-shadow' entries so the scoped ID selector suffices,
and if a true override is ever needed implement it conditionally (e.g. via a new
$block_config flag like force_important) rather than always concatenating
"!important".

In `@src/js/blocks/post-form/edit.js`:
- Around line 814-822: EmptyResponsePlaceholder currently calls console.warn
inside its render body (and similarly ErrorResponsePlaceholder elsewhere),
causing repeated logs on every render; update EmptyResponsePlaceholder and
ErrorResponsePlaceholder so their logging runs inside a useEffect hook that
depends on formId or the error/response state respectively, moving the
console.warn/console.error calls into the effect and leaving the JSX return
unchanged so the log fires only once per mount or when the relevant response
changes.

In `@webpack.config.js`:
- Around line 12-15: The custom output object currently replaces webpack's
defaults and drops settings like chunkFilename; update the export so the output
is merged with defaultConfig.output (e.g., use spread or Object.assign to
combine defaultConfig.output and your output) so that properties such as
chunkFilename provided by `@wordpress/scripts` are preserved; reference the output
key and defaultConfig (and the chunkFilename property) when making the merge.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c87b658b-3fd1-430c-8835-d83486251327

📥 Commits

Reviewing files that changed from the base of the PR and between 3252a39 and 0729000.

⛔ Files ignored due to path filters (8)
  • assets/js/account.min.js is excluded by !**/*.min.js
  • assets/js/ai-form-builder.min.js is excluded by !**/*.min.js
  • assets/js/blocks/post-form.css.map is excluded by !**/*.map
  • assets/js/blocks/post-form.js.map is excluded by !**/*.map
  • assets/js/forms-list.min.js is excluded by !**/*.min.js
  • assets/js/forms-list.min.js.map is excluded by !**/*.map, !**/*.min.js.map
  • assets/js/frontend-subscriptions.min.js is excluded by !**/*.min.js
  • assets/js/subscriptions.min.js is excluded by !**/*.min.js
📒 Files selected for processing (35)
  • assets/css/admin/form-builder.css
  • assets/css/admin/gutenblock-editor.css
  • assets/css/admin/gutenblock.css
  • assets/css/admin/subscriptions.min.css
  • assets/css/ai-form-builder.css
  • assets/css/ai-form-builder.min.css
  • assets/css/forms-list.min.css
  • assets/css/frontend-form/layout2.css
  • assets/css/frontend-form/layout4.css
  • assets/css/frontend-forms.css
  • assets/css/frontend-subscriptions.min.css
  • assets/css/frontend/account.css
  • assets/js/admin/blockFrameSetup.js
  • assets/js/admin/gutenblock.js
  • assets/js/blocks/js/blocks/post-form/block.json
  • assets/js/blocks/post-form-rtl.css
  • assets/js/blocks/post-form.asset.php
  • assets/js/blocks/post-form.css
  • assets/js/blocks/post-form.js
  • assets/less/frontend-forms.less
  • includes/Admin.php
  • includes/Blocks/PostForm.php
  • includes/Frontend.php
  • includes/Frontend/Form_Gutenberg_Block.php
  • includes/Integrations/Events_Calendar/Compatibility/TEC_V6_Compatibility.php
  • includes/templates/blocks/post-form.php
  • package.json
  • src/js/blocks/post-form/block.json
  • src/js/blocks/post-form/edit.js
  • src/js/blocks/post-form/editor.css
  • src/js/blocks/post-form/index.js
  • src/js/blocks/post-form/save.js
  • src/js/blocks/post-form/templates.js
  • webpack.config.js
  • wpuf.php
💤 Files with no reviewable changes (7)
  • includes/Admin.php
  • assets/js/admin/blockFrameSetup.js
  • includes/Integrations/Events_Calendar/Compatibility/TEC_V6_Compatibility.php
  • assets/css/admin/gutenblock.css
  • assets/js/admin/gutenblock.js
  • assets/css/frontend-form/layout4.css
  • includes/Frontend/Form_Gutenberg_Block.php

@@ -0,0 +1,289 @@
{
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Unused build artifact at a duplicated path.

This file lives at assets/js/blocks/js/blocks/post-form/block.json, a side effect of @wordpress/scripts copying block.json from the source tree into the output directory while preserving the js/blocks/post-form path. However, includes/Blocks/PostForm.php calls register_block_type() with WPUF_ROOT . '/src/js/blocks/post-form', so this copied block.json is never consulted at runtime and only adds confusion (two sources of truth that can diverge).

Consider either:

  • Point register_block_type() at the built path and add this directory to the expected output (single source of truth consumed at runtime), or
  • Suppress the copy by removing block.json from CopyWebpackPlugin patterns / excluding it in webpack.config.js, and keep src/js/blocks/post-form/block.json as the sole definition.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@assets/js/blocks/js/blocks/post-form/block.json` at line 1, The duplicated
build artifact assets/js/blocks/js/blocks/post-form/block.json is unused at
runtime because register_block_type() in includes/Blocks/PostForm.php points to
WPUF_ROOT . '/src/js/blocks/post-form', creating two divergent sources of truth;
fix by either updating register_block_type() to point to the built path (so the
runtime consumes the copied block.json) or stop the copy step in the build by
removing/excluding block.json from the CopyWebpackPlugin patterns in
webpack.config.js so only src/js/blocks/post-form/block.json remains; choose one
approach, update the corresponding path/config (register_block_type or
CopyWebpackPlugin) and remove the redundant file from the repository if
switching to the built-path option.

Comment on lines +1 to +152
/**
* Editor styles for the wpuf/post-form block.
*/

/* ── Template picker grid ── */
.wpuf-pf-templates {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 10px;
margin-top: 4px;
}

.components-base-control span.components-base-control__label,
.components-base-control label {
margin-top: .5rem;
}

/* ── Template card ── */
.wpuf-pf-template-card {
position: relative;
display: flex;
flex-direction: column;
align-items: stretch;
padding: 0;
border: 2px solid #ddd;
border-radius: 6px;
background: #fff;
cursor: pointer;
transition: border-color 0.15s ease, box-shadow 0.15s ease;
overflow: hidden;
text-align: left;
}

.wpuf-pf-template-card:hover {
border-color: #949494;
}

.wpuf-pf-template-card.is-active {
border-color: var(--wp-admin-theme-color, #3858e9);
box-shadow: 0 0 0 1px var(--wp-admin-theme-color, #3858e9);
}

/* ── Checkmark badge ── */
.wpuf-pf-template-card__badge {
display: none;
position: absolute;
top: 6px;
right: 6px;
width: 20px;
height: 20px;
border-radius: 50%;
background: var(--wp-admin-theme-color, #3858e9);
color: #fff;
align-items: center;
justify-content: center;
font-size: 12px;
line-height: 1;
z-index: 1;
}

.wpuf-pf-template-card.is-active .wpuf-pf-template-card__badge {
display: flex;
}

/* ── Realistic form mini-preview ── */
.wpuf-pf-template-preview {
padding: 12px 10px 8px;
display: flex;
flex-direction: column;
gap: 6px;
border-radius: 4px 4px 0 0;
transition: background 0.15s ease;
}

.wpuf-pf-template-preview__row {
display: flex;
flex-direction: column;
gap: 3px;
}

.wpuf-pf-template-preview__label {
height: 4px;
width: 40%;
border-radius: 2px;
opacity: 0.7;
}

.wpuf-pf-template-preview__input {
height: 16px;
border-radius: 3px;
border-style: solid;
}

.wpuf-pf-template-preview__button {
height: 14px;
width: 50%;
border-radius: 3px;
margin-top: 2px;
align-self: flex-start;
}

/* ── Card text ── */
.wpuf-pf-template-card__info {
padding: 8px 10px;
border-top: 1px solid #f0f0f0;
}

.wpuf-pf-template-card__label {
font-size: 12px;
font-weight: 600;
margin: 0;
color: #1e1e1e;
line-height: 1.4;
}

.wpuf-pf-template-card__desc {
font-size: 11px;
color: #757575;
margin: 2px 0 0;
line-height: 1.3;
}

/* ── SSR loading overlay ── */
.wpuf-ssr-loading-overlay {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background: rgba(255, 255, 255, 0.7);
z-index: 5;
}

.wpuf-ssr-loading {
width: 24px;
height: 24px;
border: 3px solid #ddd;
border-top-color: var(--wp-admin-theme-color, #3858e9);
border-radius: 50%;
animation: wpuf-spin 0.6s linear infinite;
}

@keyframes wpuf-spin {
to {
transform: rotate(360deg);
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Confirm built css matches source (drift check) and that webpack emits to this path.
diff -u src/js/blocks/post-form/editor.css assets/js/blocks/post-form.css || echo "DRIFT DETECTED"
rg -n -C2 'post-form' webpack.config.js 2>/dev/null

Repository: weDevsOfficial/wp-user-frontend

Length of output: 432


Ensure build output is consistently regenerated — minor drift detected.

The files are nearly identical, but the artifact has a trailing blank line that the source lacks. This is a minor normalization issue, but it confirms the risk mentioned: if the build process is not run before committing, the artifact and source can drift. Verify that your build/release workflow always regenerates assets/js/blocks/post-form.css from src/js/blocks/post-form/editor.css to prevent stale CSS in production.

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

In `@assets/js/blocks/post-form.css` around lines 1 - 152, The committed build
artifact assets/js/blocks/post-form.css has a trivial trailing newline drift
compared to the source src/js/blocks/post-form/editor.css (selectors like
.wpuf-pf-templates, .wpuf-pf-template-card, .wpuf-ssr-loading are present), so
regenerate the CSS from source and recommit the built file; update the local
workflow/CI to run the build step (e.g., npm/yarn script that produces
post-form.css) before commits or as a pre-merge check to prevent future drift,
and add a simple file-consistency check in CI to fail if generated assets differ
from source-produced artifacts.

Comment on lines +57 to +92
public function register_block() {
$asset_file = WPUF_ROOT . '/assets/js/blocks/post-form.asset.php';

if ( ! file_exists( $asset_file ) ) {
return;
}

$asset = require $asset_file;

wp_register_script(
'wpuf-post-form-editor',
WPUF_ROOT_URI . '/assets/js/blocks/post-form.js',
$asset['dependencies'],
$asset['version'],
true
);

wp_register_style(
'wpuf-post-form-editor-style',
WPUF_ROOT_URI . '/assets/js/blocks/post-form.css',
[ 'wpuf-frontend-forms', 'wpuf-layout1' ],
$asset['version']
);

wp_localize_script(
'wpuf-post-form-editor',
'wpufPostForm',
$this->get_editor_data()
);

$block_json_path = WPUF_ROOT . '/src/js/blocks/post-form';

register_block_type( $block_json_path, [
'render_callback' => [ $this, 'render' ],
] );
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Move editor-only registration off the frontend init path.

register_block() runs on every init — including frontend and REST/cron requests — yet the registered editor script/style and the get_editor_data() query are only useful inside the block editor. Notably, get_editor_data() unconditionally runs a get_posts() query for all published wpuf_forms posts on every page load, which is unnecessary overhead on the frontend.

Consider gating the editor asset work to editor contexts (e.g., enqueue_block_editor_assets for localization/enqueue, or at least is_admin()/REST context for registration), while keeping register_block_type() on init so the block remains renderable.

♻️ Suggested restructure
 public function __construct() {
     add_action( 'init', [ $this, 'register_block' ] );
+    add_action( 'enqueue_block_editor_assets', [ $this, 'localize_editor_data' ] );
     add_filter( 'block_categories_all', [ $this, 'register_block_category' ] );
 }

Then move wp_localize_script() + get_editor_data() into localize_editor_data() so the DB query only runs when the editor loads.

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

In `@includes/Blocks/PostForm.php` around lines 57 - 92, register_block()
currently registers editor scripts/styles and calls get_editor_data() on every
init (frontend/REST), causing unnecessary DB queries; change it so
register_block_type( ...) stays in register_block() on init but move
wp_register_script, wp_register_style and wp_localize_script/get_editor_data()
out of init and into an editor-only hook (e.g., hook a new
localize_editor_data() or enqueue_editor_assets() to enqueue_block_editor_assets
or at minimum is_admin()/rest checks) so the get_editor_data() query only runs
when the block editor loads; update references to 'wpuf-post-form-editor' and
'wpufPostForm' inside the new editor hook and ensure register_block_type still
points to [ $this, 'render' ].

Comment thread includes/Frontend.php
|| class_exists( '\Elementor\Plugin' )
|| $this->dokan_is_seller_dashboard() ) {
|| $this->dokan_is_seller_dashboard()
|| ( isset( $post->post_content ) && has_block( 'wpuf/post-form', $post ) ) ) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check whether the block's PHP render path enqueues its own runtime assets
# (would compensate for the has_block() gap here).
fd -t f 'PostForm.php' includes/Blocks
rg -n -C3 'wp_enqueue_(script|style)|wpuf-frontend-form|wpuf-frontend-forms' includes/Blocks/PostForm.php includes/templates/blocks/post-form.php 2>/dev/null

Repository: weDevsOfficial/wp-user-frontend

Length of output: 558


🏁 Script executed:

# Get full PostForm.php to see if there's a render_callback and what it does
cat -n includes/Blocks/PostForm.php | head -150

Repository: weDevsOfficial/wp-user-frontend

Length of output: 5417


🏁 Script executed:

# Check if post-form.php template file exists and enqueues assets
ls -la includes/templates/blocks/post-form.php 2>/dev/null && echo "---FILE EXISTS---" && head -50 includes/templates/blocks/post-form.php

Repository: weDevsOfficial/wp-user-frontend

Length of output: 2598


🏁 Script executed:

# Check how Frontend.php uses has_block() and in what context
cat -n includes/Frontend.php | grep -A 10 -B 10 "has_block.*post-form"

Repository: weDevsOfficial/wp-user-frontend

Length of output: 1299


🏁 Script executed:

# Get the render() method from PostForm.php
sed -n '150,400p' includes/Blocks/PostForm.php

Repository: weDevsOfficial/wp-user-frontend

Length of output: 13634


🏁 Script executed:

# Continue reading PostForm.php render() method from line 400 onwards
sed -n '400,500p' includes/Blocks/PostForm.php

Repository: weDevsOfficial/wp-user-frontend

Length of output: 1992


🏁 Script executed:

# Check if the [wpuf_form] shortcode enqueues its own assets
rg -n 'wp_enqueue_|add_shortcode.*wpuf_form' includes/ -A 10 | head -100

Repository: weDevsOfficial/wp-user-frontend

Length of output: 6912


🏁 Script executed:

# Check what shortcodes are available
fd -t f '*.php' includes/ -x grep -l 'add_shortcode' {} \;

Repository: weDevsOfficial/wp-user-frontend

Length of output: 360


🏁 Script executed:

# Look at the full post-form.php template to see if it calls the shortcode
tail -100 includes/templates/blocks/post-form.php

Repository: weDevsOfficial/wp-user-frontend

Length of output: 5432


🏁 Script executed:

# Search for wpuf_form shortcode registration
rg -n "add_shortcode.*wpuf_form" includes/ -B 2 -A 5

Repository: weDevsOfficial/wp-user-frontend

Length of output: 1121


🏁 Script executed:

# Find the add_post_shortcode method and see if it enqueues assets
rg -n "function add_post_shortcode" includes/ -A 30

Repository: weDevsOfficial/wp-user-frontend

Length of output: 2618


🏁 Script executed:

# Also check if there's an enqueue hook for render_block
rg -n "render_block|enqueue_block_assets" includes/ -B 2 -A 5

Repository: weDevsOfficial/wp-user-frontend

Length of output: 57


🏁 Script executed:

# Check what render_form() does regarding enqueuing
rg -n "function render_form" includes/Frontend/ -A 50 | head -100

Repository: weDevsOfficial/wp-user-frontend

Length of output: 57


🏁 Script executed:

# Look for where wpuf-frontend-form and wpuf-frontend-forms are enqueued
rg -n "wpuf-frontend-form" includes/ -B 3 -A 1

Repository: weDevsOfficial/wp-user-frontend

Length of output: 5590


🏁 Script executed:

# Check if there's a render_block hook anywhere that handles wpuf blocks
rg -n "render_block|enqueue_block_assets" includes/ -B 2 -A 8

Repository: weDevsOfficial/wp-user-frontend

Length of output: 57


🏁 Script executed:

# Check the actual flow: does post-form.php call do_shortcode?
grep -n "do_shortcode\|wpuf_form" includes/templates/blocks/post-form.php

Repository: weDevsOfficial/wp-user-frontend

Length of output: 348


🏁 Script executed:

# Check if the block registration in block.json includes script/style handles
cat includes/templates/blocks/post-form.php | head -30

Repository: weDevsOfficial/wp-user-frontend

Length of output: 1493


🏁 Script executed:

# Look at the block.json or JS to see if there's frontend script registration
fd -type f "post-form" src/js/blocks/ -o includes/Blocks/

Repository: weDevsOfficial/wp-user-frontend

Length of output: 246


🏁 Script executed:

# Look at the block.json for post-form
find . -name "block.json" | grep post-form

Repository: weDevsOfficial/wp-user-frontend

Length of output: 162


🏁 Script executed:

# Check if block.json exists and what it contains
find . -path "*/blocks/post-form/block.json" -o -path "*/post-form.json" 2>/dev/null | xargs cat 2>/dev/null

Repository: weDevsOfficial/wp-user-frontend

Length of output: 10900


has_block() only scans post_content — block placements in FSE templates, template parts, or widget areas won't trigger asset enqueue.

The wpuf/post-form block's render_callback does not enqueue frontend assets (block.json has no script or style fields). Asset enqueuing relies entirely on the has_block( 'wpuf/post-form', $post ) check in Frontend.php line 58, which only inspects $post->post_content.

If a site builder places the block inside a block-theme template, template part, reusable block, or widget area, has_block() returns false and the frontend styles/scripts (wpuf-frontend-forms, wpuf-frontend-form) are not enqueued — resulting in an unstyled or non-functional form.

Consider hooking into render_block (filter or action) to detect wpuf/post-form renders and enqueue assets on-demand, covering placements beyond post content.

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

In `@includes/Frontend.php` at line 58, The current Frontend.php check uses
has_block('wpuf/post-form', $post) and misses placements outside post_content;
instead add a render-time detector using the render_block (filter or action) to
catch when the wpuf/post-form block is rendered and enqueue the frontend asset
handles (wpuf-frontend-forms, wpuf-frontend-form) there; update or remove the
has_block-dependent path and implement a callback (e.g., on_render_block) that
checks the block name === 'wpuf/post-form' and calls
wp_enqueue_style/wp_enqueue_script so assets load for blocks rendered from
templates, template parts, reusable blocks, or widgets.

Comment on lines +218 to +220
$ms_active_bg = $block_config['ms_active_bg_color'] ?: ( $form_settings_meta['ms_active_bgcolor'] ?? '#00a0d2' );
$ms_active_txt = $block_config['ms_active_text_color'] ?: ( $form_settings_meta['ms_ac_txt_color'] ?? '#ffffff' );
$ms_inactive = $block_config['ms_inactive_bg_color'] ?: ( $form_settings_meta['ms_bgcolor'] ?? '#e4e4e4' );
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Form-settings meta values flow into CSS without sanitization.

$form_settings_meta['ms_active_bgcolor'], ['ms_ac_txt_color'], ['ms_bgcolor'] come straight from post meta. They are interpolated into CSS declarations (lines 223–261) via the same esc_attr() path that is insufficient for CSS contexts (see the separate comment on $style_output). A form administrator could inject CSS by saving a crafted color value. Wrap the fallback with sanitize_hex_color() (and default to the hex already used) so only valid hex colors reach the stylesheet:

🛡️ Sanitize meta fallbacks
-        $ms_active_bg  = $block_config['ms_active_bg_color'] ?: ( $form_settings_meta['ms_active_bgcolor'] ?? '#00a0d2' );
-        $ms_active_txt = $block_config['ms_active_text_color'] ?: ( $form_settings_meta['ms_ac_txt_color'] ?? '#ffffff' );
-        $ms_inactive   = $block_config['ms_inactive_bg_color'] ?: ( $form_settings_meta['ms_bgcolor'] ?? '#e4e4e4' );
+        $ms_active_bg  = $block_config['ms_active_bg_color']
+            ?: ( sanitize_hex_color( $form_settings_meta['ms_active_bgcolor'] ?? '' ) ?: '#00a0d2' );
+        $ms_active_txt = $block_config['ms_active_text_color']
+            ?: ( sanitize_hex_color( $form_settings_meta['ms_ac_txt_color'] ?? '' ) ?: '#ffffff' );
+        $ms_inactive   = $block_config['ms_inactive_bg_color']
+            ?: ( sanitize_hex_color( $form_settings_meta['ms_bgcolor'] ?? '' ) ?: '#e4e4e4' );
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@includes/templates/blocks/post-form.php` around lines 218 - 220, The
meta-sourced color fallbacks ($form_settings_meta['ms_active_bgcolor'],
['ms_ac_txt_color'], ['ms_bgcolor']) assigned to $ms_active_bg, $ms_active_txt
and $ms_inactive are not sanitized for CSS and can allow injection; update those
assignments to pass the meta values through WordPress's sanitize_hex_color() and
if that returns empty/invalid, fall back to the existing literal hex defaults
(e.g. '#00a0d2', '#ffffff', '#e4e4e4') so only valid hex colors reach the
stylesheet before further escaping/output (keep the same variable names
$ms_active_bg, $ms_active_txt, $ms_inactive).

Comment on lines +416 to +420
$shortcode_output = preg_replace(
'/<button\s+class="wpuf-multistep-(prev|next)-btn([^"]*)"/',
'<button disabled class="wpuf-multistep-$1-btn$2"',
$shortcode_output
);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Fragile regex: requires class to be the first attribute on <button>.

/<button\s+class="wpuf-multistep-(prev|next)-btn([^"]*)"/ won't match if WPUF (now or later) emits other attributes before class (e.g., type, id, data-*). Preview buttons would then remain clickable. Make it order-agnostic:

♻️ Order-agnostic pattern
-                $shortcode_output = preg_replace(
-                    '/<button\s+class="wpuf-multistep-(prev|next)-btn([^"]*)"/',
-                    '<button disabled class="wpuf-multistep-$1-btn$2"',
-                    $shortcode_output
-                );
+                $shortcode_output = preg_replace(
+                    '/<button(?![^>]*\bdisabled\b)([^>]*?\bclass="[^"]*\bwpuf-multistep-(?:prev|next)-btn[^"]*")/i',
+                    '<button disabled$1',
+                    $shortcode_output
+                );
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@includes/templates/blocks/post-form.php` around lines 416 - 420, The current
preg_replace on $shortcode_output uses a regex that assumes class is the first
attribute on <button> (the pattern in the preg_replace call), which fails when
other attributes (type, id, data-*) appear before class; update the regex used
in the preg_replace call so it matches a <button> element regardless of
attribute order by searching for a class attribute that contains
"wpuf-multistep-(prev|next)-btn" anywhere among the tag attributes, then inject
the disabled attribute while preserving all existing attributes and their order;
modify only the pattern passed to preg_replace (the $shortcode_output
replacement logic) to be order-agnostic and case-insensitive and ensure it still
targets the same class fragment.

Comment on lines +4 to +11
import {
InspectorControls,
PanelColorSettings,
useBlockProps,
useSettings,
__experimentalFontFamilyControl as FontFamilyControl,
__experimentalFontAppearanceControl as FontAppearanceControl,
} from '@wordpress/block-editor';
Copy link
Copy Markdown

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:

#!/bin/bash
# Inspect the plugin's WordPress version requirements
rg -nP --type=php -C1 '(Requires at least|WPUF_MIN_WP_VERSION|requires_wp)' -g '!vendor/**'
fd -e php 'wp-user-frontend.php' | head -5 | xargs -r cat | head -40

Repository: weDevsOfficial/wp-user-frontend

Length of output: 57


🌐 Web query:

@wordpress/block-editor useSettings hook WordPress version introduced

💡 Result:

The useSettings hook from @wordpress/block-editor was introduced in WordPress 6.5.

Citations:


🏁 Script executed:

#!/bin/bash
# Find the main plugin file and its header information
find . -name 'wp-user-frontend.php' -o -name 'README.md' -o -name 'readme.txt' | head -10 | xargs -r head -50

Repository: weDevsOfficial/wp-user-frontend

Length of output: 23416


🏁 Script executed:

#!/bin/bash
# Search for WordPress version requirements in all files
rg -i 'requires.*wordpress|requires.*at least|requires_wp|min.*version' --type=php --type=txt --type=json -g '!vendor/**' --max-count=5

Repository: weDevsOfficial/wp-user-frontend

Length of output: 2563


🏁 Script executed:

#!/bin/bash
# Verify the import statement at lines 4-11 of edit.js
cat -n src/js/blocks/post-form/edit.js | sed -n '1,15p'

Repository: weDevsOfficial/wp-user-frontend

Length of output: 733


Update plugin minimum WordPress version to 6.5 or replace useSettings with fallback.

The plugin declares Requires at least: 5.0 in readme.txt, but imports useSettings from @wordpress/block-editor, which was introduced in WordPress 6.5. For users on WordPress 5.0–6.4, this hook will be undefined, causing the editor to crash when opening the block.

Resolve this by either:

  • Bumping the plugin's Requires at least header to 6.5, or
  • Replacing useSettings with useSetting (note: returns a single value, not a [value, setter] pair; check the return shape matches your usage at lines using this hook).
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/js/blocks/post-form/edit.js` around lines 4 - 11, The code imports
useSettings from `@wordpress/block-editor` which was added in WP 6.5; update the
plugin to require WordPress 6.5 by changing the readme.txt "Requires at least"
header to 6.5, or replace useSettings with the older useSetting hook and adjust
call sites (where useSettings is used in this file) to account for useSetting
returning a single value (not [value, setter])—update any destructuring or
assignments that expect a pair and ensure any setters are replaced with
appropriate state management.

Comment on lines +254 to +271
// SSR loading overlay state
const [isUpdating, setIsUpdating] = useState(false);
const debounceTimerRef = useRef(null);
const isFirstRender = useRef(true);

useEffect(() => {
if (isFirstRender.current) {
isFirstRender.current = false;
return;
}
if (debounceTimerRef.current) {
clearTimeout(debounceTimerRef.current);
}
debounceTimerRef.current = setTimeout(() => {
setIsUpdating(true);
}, 150);
return () => clearTimeout(debounceTimerRef.current);
}, [attributes]);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

isUpdating can get stuck on if SSR never returns a Loading state.

The only path that clears isUpdating is LoadingResponsePlaceholder's unmount effect (lines 805–813). If ServerSideRender resolves from cache without going through the Loading… state, or if EmptyResponsePlaceholder / ErrorResponsePlaceholder is shown instead, the placeholder never mounts, so its cleanup never fires and the "Updating preview…" overlay stays forever.

Safer to also clear isUpdating in a settled-state effect, or drive it from ServerSideRender's lifecycle rather than the attributes-changed timer.

♻️ Defensive cleanup
     debounceTimerRef.current = setTimeout(() => {
         setIsUpdating(true);
     }, 150);
-    return () => clearTimeout(debounceTimerRef.current);
+    // Auto-clear after a reasonable timeout as a safety net in case the
+    // Loading placeholder never mounts (e.g., cached SSR, empty/error path).
+    const safetyTimer = setTimeout( () => setIsUpdating( false ), 4000 );
+    return () => {
+        clearTimeout( debounceTimerRef.current );
+        clearTimeout( safetyTimer );
+    };
 }, [attributes]);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/js/blocks/post-form/edit.js` around lines 254 - 271, The isUpdating flag
can remain true if ServerSideRender never mounts LoadingResponsePlaceholder;
modify the logic so isUpdating is cleared when the server render settles or when
non-loading placeholders mount: update the attributes useEffect (which uses
isUpdating, setIsUpdating, debounceTimerRef) to also clear/setIsUpdating(false)
in the settled/error/empty paths or add a separate effect tied to
ServerSideRender's lifecycle (or to any state/prop that indicates a settled
response) that calls setIsUpdating(false); ensure any debounceTimerRef timeouts
are cleared and setIsUpdating(false) runs on unmount so
LoadingResponsePlaceholder's unmount is not the sole mechanism for clearing
isUpdating.

Comment on lines +276 to +311
const handleTemplateSelect = useCallback(
(template) => {
if (template.id === activeTemplate) {
return;
}

// Save current state for undo
const snapshot = { ...attributes };
prevAttrsRef.current = snapshot;

// Apply immediately
setAttributes(template.attributes);

// Show snackbar with undo
createNotice(
'info',
template.label + ' ' + __('template applied.', 'wp-user-frontend'),
{
type: 'snackbar',
isDismissible: true,
actions: [
{
label: __('Undo', 'wp-user-frontend'),
onClick: () => {
if (prevAttrsRef.current) {
setAttributes(prevAttrsRef.current);
prevAttrsRef.current = null;
}
},
},
],
}
);
},
[activeTemplate, attributes, setAttributes, createNotice]
);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Undo snapshot isn't cleared when another template is chosen.

handleTemplateSelect overwrites prevAttrsRef.current on each non-no-op selection and only nulls it after the Undo action fires. If the user picks Template A, then picks Template B without hitting Undo on A's snackbar, then finally clicks Undo on A's (still-visible or re-appearing) snackbar, they'll be rolled back to the post-A/pre-B state instead of the pre-A state they expect. More importantly, if the Undo action for A's notice is clicked after B was applied, it uses B's snapshot (of A's style), causing surprising results.

Since createNotice returns an id and removeNotice exists, consider dismissing the previous snackbar when a new template is applied, or capturing the snapshot via closure instead of a shared ref so each snackbar is bound to its own snapshot:

♻️ Per-notice snapshot via closure
-        const snapshot = { ...attributes };
-        prevAttrsRef.current = snapshot;
-
-        // Apply immediately
+        // Capture snapshot in closure so each notice's Undo restores
+        // the state it was created against.
+        const snapshot = { ...attributes };
         setAttributes(template.attributes);

         // Show snackbar with undo
         createNotice(
             'info',
             template.label + ' ' + __('template applied.', 'wp-user-frontend'),
             {
                 type: 'snackbar',
                 isDismissible: true,
                 actions: [
                     {
                         label: __('Undo', 'wp-user-frontend'),
-                        onClick: () => {
-                            if (prevAttrsRef.current) {
-                                setAttributes(prevAttrsRef.current);
-                                prevAttrsRef.current = null;
-                            }
-                        },
+                        onClick: () => setAttributes( snapshot ),
                     },
                 ],
             }
         );
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/js/blocks/post-form/edit.js` around lines 276 - 311, handleTemplateSelect
currently stores the undo snapshot in the shared prevAttrsRef which gets
overwritten by subsequent template selections; change it to either (A) capture
the snapshot in the createNotice closure (e.g., const snapshot = { ...attributes
} local to handleTemplateSelect and reference that inside the notice's onClick)
so each snackbar has its own immutable snapshot, or (B) track the notice id
returned from createNotice and call removeNotice(previousNoticeId) before
creating a new notice and also clear prevAttrsRef when removing; update
references to prevAttrsRef, createNotice, removeNotice, setAttributes, and
handleTemplateSelect accordingly so each Undo restores the correct per-notice
snapshot and no shared state is reused.

Comment on lines +4 to +347
export const TEMPLATES = [
{
id: 'default',
label: 'Default',
description: 'Clean, inherits theme styles',
preview: {
bg: '#ffffff',
border: '#dddddd',
button: '#0073aa',
text: '#333333',
},
attributes: {
activeTemplate: 'default',
style: {
color: {},
},
labelFontSize: '14px',
labelColor: '#333333',
labelFontWeight: 'normal',
labelFontFamily: '',
labelFontStyle: '',
helpTextColor: '#767676',
helpTextFontFamily: '',
helpTextFontSize: '12px',
helpTextFontStyle: '',
helpTextFontWeight: '',
fieldBorder: {
color: '#dddddd',
style: 'solid',
width: '1px',
},
fieldBorderRadius: '4px',
fieldPaddingV: '8px',
fieldPaddingH: '12px',
fieldBackgroundColor: '#ffffff',
fieldTextColor: '#333333',
fieldPlaceholderColor: '#aaaaaa',
fieldFontFamily: '',
fieldFontSize: '14px',
fieldFontStyle: '',
fieldFontWeight: '',
fieldMarginBottom: '16px',
fieldFocusBorderColor: '#0073aa',
buttonBackgroundColor: '#0073aa',
buttonTextColor: '#ffffff',
buttonBorderColor: '',
buttonBorderWidth: '0px',
buttonBorderRadius: '4px',
buttonFontSize: '14px',
buttonFontFamily: '',
buttonFontStyle: '',
buttonFontWeight: '',
buttonPaddingV: '10px',
buttonPaddingH: '20px',
uploadButtonBackgroundColor: '#f0f0f0',
uploadButtonTextColor: '#333333',
uploadButtonBorderColor: '#dddddd',
uploadButtonBorderWidth: '1px',
uploadButtonBorderRadius: '4px',
uploadButtonFontSize: '13px',
uploadButtonFontFamily: '',
uploadButtonFontStyle: '',
uploadButtonFontWeight: '',
uploadButtonPaddingV: '8px',
uploadButtonPaddingH: '16px',
errorMessageColor: '#cc0000',
successMessageColor: '#00a32a',
},
},
{
id: 'dark',
label: 'Dark',
description: 'Dark background, light text',
preview: {
bg: '#1e1e2e',
border: '#3d3d5c',
button: '#7c3aed',
text: '#f0f0f0',
},
attributes: {
activeTemplate: 'dark',
style: {
color: {
background: '#1e1e2e',
},
},
labelFontSize: '14px',
labelColor: '#e0e0e0',
labelFontWeight: 'normal',
labelFontFamily: '',
labelFontStyle: '',
helpTextColor: '#a0a0b0',
helpTextFontFamily: '',
helpTextFontSize: '12px',
helpTextFontStyle: '',
helpTextFontWeight: '',
fieldBorder: {
color: '#3d3d5c',
style: 'solid',
width: '1px',
},
fieldBorderRadius: '6px',
fieldPaddingV: '10px',
fieldPaddingH: '14px',
fieldBackgroundColor: '#2a2a3e',
fieldTextColor: '#f0f0f0',
fieldPlaceholderColor: '#6b6b8a',
fieldFontFamily: '',
fieldFontSize: '14px',
fieldFontStyle: '',
fieldFontWeight: '',
fieldMarginBottom: '18px',
fieldFocusBorderColor: '#7c3aed',
buttonBackgroundColor: '#7c3aed',
buttonTextColor: '#ffffff',
buttonBorderColor: '',
buttonBorderWidth: '0px',
buttonBorderRadius: '6px',
buttonFontSize: '14px',
buttonFontFamily: '',
buttonFontStyle: '',
buttonFontWeight: '',
buttonPaddingV: '12px',
buttonPaddingH: '24px',
uploadButtonBackgroundColor: '#2a2a3e',
uploadButtonTextColor: '#e0e0e0',
uploadButtonBorderColor: '#3d3d5c',
uploadButtonBorderWidth: '1px',
uploadButtonBorderRadius: '6px',
uploadButtonFontSize: '13px',
uploadButtonFontFamily: '',
uploadButtonFontStyle: '',
uploadButtonFontWeight: '',
uploadButtonPaddingV: '8px',
uploadButtonPaddingH: '16px',
errorMessageColor: '#f87171',
successMessageColor: '#34d399',
},
},
{
id: 'colorful',
label: 'Colorful',
description: 'Vibrant purple accent',
preview: {
bg: '#fdf4ff',
border: '#c084fc',
button: '#9333ea',
text: '#4a044e',
},
attributes: {
activeTemplate: 'colorful',
style: {
color: {},
},
labelFontSize: '14px',
labelColor: '#7e22ce',
labelFontWeight: '600',
labelFontFamily: '',
labelFontStyle: '',
helpTextColor: '#a855f7',
helpTextFontFamily: '',
helpTextFontSize: '12px',
helpTextFontStyle: '',
helpTextFontWeight: '',
fieldBorder: {
color: '#c084fc',
style: 'solid',
width: '2px',
},
fieldBorderRadius: '8px',
fieldPaddingV: '10px',
fieldPaddingH: '14px',
fieldBackgroundColor: '#fdf4ff',
fieldTextColor: '#4a044e',
fieldPlaceholderColor: '#d8b4fe',
fieldFontFamily: '',
fieldFontSize: '14px',
fieldFontStyle: '',
fieldFontWeight: '',
fieldMarginBottom: '20px',
fieldFocusBorderColor: '#7e22ce',
buttonBackgroundColor: '#9333ea',
buttonTextColor: '#ffffff',
buttonBorderColor: '',
buttonBorderWidth: '0px',
buttonBorderRadius: '8px',
buttonFontSize: '15px',
buttonFontFamily: '',
buttonFontStyle: '',
buttonFontWeight: '',
buttonPaddingV: '12px',
buttonPaddingH: '28px',
uploadButtonBackgroundColor: '#f3e8ff',
uploadButtonTextColor: '#7e22ce',
uploadButtonBorderColor: '#c084fc',
uploadButtonBorderWidth: '2px',
uploadButtonBorderRadius: '8px',
uploadButtonFontSize: '13px',
uploadButtonFontFamily: '',
uploadButtonFontStyle: '',
uploadButtonFontWeight: '',
uploadButtonPaddingV: '8px',
uploadButtonPaddingH: '16px',
errorMessageColor: '#be123c',
successMessageColor: '#16a34a',
},
},
{
id: 'minimal',
label: 'Minimal',
description: 'Borderless fields, understated',
preview: {
bg: '#ffffff',
border: '#e5e5e5',
button: '#111111',
text: '#111111',
},
attributes: {
activeTemplate: 'minimal',
style: {
color: {},
},
labelFontSize: '13px',
labelColor: '#555555',
labelFontWeight: 'normal',
labelFontFamily: '',
labelFontStyle: '',
helpTextColor: '#999999',
helpTextFontFamily: '',
helpTextFontSize: '11px',
helpTextFontStyle: '',
helpTextFontWeight: '',
fieldBorder: {
color: '#dddddd',
style: 'solid',
width: '1px',
},
fieldBorderRadius: '0px',
fieldPaddingV: '8px',
fieldPaddingH: '4px',
fieldBackgroundColor: '#ffffff',
fieldTextColor: '#111111',
fieldPlaceholderColor: '#cccccc',
fieldFontFamily: '',
fieldFontSize: '13px',
fieldFontStyle: '',
fieldFontWeight: '',
fieldMarginBottom: '20px',
fieldFocusBorderColor: '#111111',
buttonBackgroundColor: '#111111',
buttonTextColor: '#ffffff',
buttonBorderColor: '',
buttonBorderWidth: '0px',
buttonBorderRadius: '2px',
buttonFontSize: '13px',
buttonFontFamily: '',
buttonFontStyle: '',
buttonFontWeight: '',
buttonPaddingV: '10px',
buttonPaddingH: '24px',
uploadButtonBackgroundColor: '#ffffff',
uploadButtonTextColor: '#555555',
uploadButtonBorderColor: '#e5e5e5',
uploadButtonBorderWidth: '0px',
uploadButtonBorderRadius: '0px',
uploadButtonFontSize: '13px',
uploadButtonFontFamily: '',
uploadButtonFontStyle: '',
uploadButtonFontWeight: '',
uploadButtonPaddingV: '8px',
uploadButtonPaddingH: '4px',
errorMessageColor: '#cc0000',
successMessageColor: '#008000',
},
},
{
id: 'bold',
label: 'Bold',
description: 'Strong borders, high contrast',
preview: {
bg: '#ffffff',
border: '#000000',
button: '#f59e0b',
text: '#000000',
},
attributes: {
activeTemplate: 'bold',
style: {
color: {},
},
labelFontSize: '15px',
labelColor: '#000000',
labelFontWeight: '700',
labelFontFamily: '',
labelFontStyle: '',
helpTextColor: '#555555',
helpTextFontFamily: '',
helpTextFontSize: '13px',
helpTextFontStyle: '',
helpTextFontWeight: '',
fieldBorder: {
color: '#000000',
style: 'solid',
width: '2px',
},
fieldBorderRadius: '0px',
fieldPaddingV: '10px',
fieldPaddingH: '14px',
fieldBackgroundColor: '#ffffff',
fieldTextColor: '#000000',
fieldPlaceholderColor: '#999999',
fieldFontFamily: '',
fieldFontSize: '15px',
fieldFontStyle: '',
fieldFontWeight: '',
fieldMarginBottom: '20px',
fieldFocusBorderColor: '#f59e0b',
buttonBackgroundColor: '#f59e0b',
buttonTextColor: '#000000',
buttonBorderColor: '#000000',
buttonBorderWidth: '2px',
buttonBorderRadius: '0px',
buttonFontSize: '15px',
buttonFontFamily: '',
buttonFontStyle: '',
buttonFontWeight: '',
buttonPaddingV: '12px',
buttonPaddingH: '28px',
uploadButtonBackgroundColor: '#ffffff',
uploadButtonTextColor: '#000000',
uploadButtonBorderColor: '#000000',
uploadButtonBorderWidth: '2px',
uploadButtonBorderRadius: '0px',
uploadButtonFontSize: '13px',
uploadButtonFontFamily: '',
uploadButtonFontStyle: '',
uploadButtonFontWeight: '',
uploadButtonPaddingV: '8px',
uploadButtonPaddingH: '16px',
errorMessageColor: '#cc0000',
successMessageColor: '#166534',
},
},
];
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Template label and description strings are not translatable.

The label and description values for each preset are rendered in the block editor's template picker UI (via TemplateCard in edit.js), but they're plain string literals and bypass the wp-user-frontend text domain. Wrap them with __() so translators can localize them.

🌐 Proposed fix (applies to all 5 presets)
+import { __ } from '@wordpress/i18n';
+
 export const TEMPLATES = [
     {
         id: 'default',
-        label: 'Default',
-        description: 'Clean, inherits theme styles',
+        label: __( 'Default', 'wp-user-frontend' ),
+        description: __( 'Clean, inherits theme styles', 'wp-user-frontend' ),
         // …
     },
     // Apply the same __() wrapping to 'dark', 'colorful', 'minimal', 'bold'.
 ];
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/js/blocks/post-form/templates.js` around lines 4 - 347, TEMPLATES preset
objects use plain string literals for label and description (e.g.,
TEMPLATES[*].label and TEMPLATES[*].description) so they aren’t localizable;
update each preset in the TEMPLATES array to wrap those string literals with the
localization function __(..., 'wp-user-frontend') so the TemplateCard UI in
edit.js receives translatable strings (apply to all presets:
'default','dark','colorful','minimal','bold').

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