Feature/post form gutenberg block#1850
Conversation
|
Warning Rate limit exceeded
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 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 configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: ⛔ Files ignored due to path filters (6)
📒 Files selected for processing (10)
WalkthroughThis 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
Estimated code review effort🎯 4 (Complex) | ⏱️ ~75 minutes Suggested labels
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
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 | 🟡 MinorCompiled CSS appears stale — regenerate
frontend-forms.css.The AI summary states the
text-shadowon.wpuf-progress-percentagewas removed here, and indeed this source block no longer contains it. However,assets/css/frontend-forms.css(lines 1153–1160) still emitstext-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 refreshedfrontend-forms.cssso 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!importantonwidth: 100%.The previous shared rule used plain
width: 100%without!important. Since the selector now already excludesfile/radio/checkbox/submitvia:not(), there's no internal rule left for!importantto 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!importantunless 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"])oninputcorrectly prevents the green#00C14Bfocus/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:visitedpseudo-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
selectrule (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 dropselect, you now maintain two copies of the same declaration block. A cleaner approach is to keepselectin 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!importantwill 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!importanthere is when fighting specific theme rules that themselves use!important. Consider dropping!importantfrom 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.errorinvoked during render.Calling
console.warndirectly in the body ofEmptyResponsePlaceholderandErrorResponsePlaceholdermeans 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 auseEffectso 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: MergeoutputwithdefaultConfigto preserve webpack defaults.The
outputconfig is completely replaced rather than merged withdefaultConfig, discarding settings likechunkFilenamethat@wordpress/scripts31.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 onget_block_wrapper_attributes().The regex
'/\s*id="[^"]*"/'only matches double-quotedidattributes. It will miss single-quoted output and is sensitive to future core changes inget_block_wrapper_attributes(). Also, core only emitsid="..."when the block has ananchorattribute set, so in most cases thispreg_replaceis 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
⛔ Files ignored due to path filters (8)
assets/js/account.min.jsis excluded by!**/*.min.jsassets/js/ai-form-builder.min.jsis excluded by!**/*.min.jsassets/js/blocks/post-form.css.mapis excluded by!**/*.mapassets/js/blocks/post-form.js.mapis excluded by!**/*.mapassets/js/forms-list.min.jsis excluded by!**/*.min.jsassets/js/forms-list.min.js.mapis excluded by!**/*.map,!**/*.min.js.mapassets/js/frontend-subscriptions.min.jsis excluded by!**/*.min.jsassets/js/subscriptions.min.jsis excluded by!**/*.min.js
📒 Files selected for processing (35)
assets/css/admin/form-builder.cssassets/css/admin/gutenblock-editor.cssassets/css/admin/gutenblock.cssassets/css/admin/subscriptions.min.cssassets/css/ai-form-builder.cssassets/css/ai-form-builder.min.cssassets/css/forms-list.min.cssassets/css/frontend-form/layout2.cssassets/css/frontend-form/layout4.cssassets/css/frontend-forms.cssassets/css/frontend-subscriptions.min.cssassets/css/frontend/account.cssassets/js/admin/blockFrameSetup.jsassets/js/admin/gutenblock.jsassets/js/blocks/js/blocks/post-form/block.jsonassets/js/blocks/post-form-rtl.cssassets/js/blocks/post-form.asset.phpassets/js/blocks/post-form.cssassets/js/blocks/post-form.jsassets/less/frontend-forms.lessincludes/Admin.phpincludes/Blocks/PostForm.phpincludes/Frontend.phpincludes/Frontend/Form_Gutenberg_Block.phpincludes/Integrations/Events_Calendar/Compatibility/TEC_V6_Compatibility.phpincludes/templates/blocks/post-form.phppackage.jsonsrc/js/blocks/post-form/block.jsonsrc/js/blocks/post-form/edit.jssrc/js/blocks/post-form/editor.csssrc/js/blocks/post-form/index.jssrc/js/blocks/post-form/save.jssrc/js/blocks/post-form/templates.jswebpack.config.jswpuf.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 @@ | |||
| { | |||
There was a problem hiding this comment.
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.jsonfromCopyWebpackPluginpatterns / excluding it inwebpack.config.js, and keepsrc/js/blocks/post-form/block.jsonas 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.
| /** | ||
| * 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); | ||
| } | ||
| } | ||
|
|
There was a problem hiding this comment.
🧩 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/nullRepository: 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.
| 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' ], | ||
| ] ); | ||
| } |
There was a problem hiding this comment.
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' ].
| || class_exists( '\Elementor\Plugin' ) | ||
| || $this->dokan_is_seller_dashboard() ) { | ||
| || $this->dokan_is_seller_dashboard() | ||
| || ( isset( $post->post_content ) && has_block( 'wpuf/post-form', $post ) ) ) { |
There was a problem hiding this comment.
🧩 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/nullRepository: 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 -150Repository: 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.phpRepository: 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.phpRepository: 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.phpRepository: 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 -100Repository: 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.phpRepository: 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 5Repository: 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 30Repository: 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 5Repository: 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 -100Repository: 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 1Repository: 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 8Repository: 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.phpRepository: 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 -30Repository: 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-formRepository: 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/nullRepository: 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.
| $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' ); |
There was a problem hiding this comment.
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).
| $shortcode_output = preg_replace( | ||
| '/<button\s+class="wpuf-multistep-(prev|next)-btn([^"]*)"/', | ||
| '<button disabled class="wpuf-multistep-$1-btn$2"', | ||
| $shortcode_output | ||
| ); |
There was a problem hiding this comment.
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.
| import { | ||
| InspectorControls, | ||
| PanelColorSettings, | ||
| useBlockProps, | ||
| useSettings, | ||
| __experimentalFontFamilyControl as FontFamilyControl, | ||
| __experimentalFontAppearanceControl as FontAppearanceControl, | ||
| } from '@wordpress/block-editor'; |
There was a problem hiding this comment.
🧩 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 -40Repository: 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:
- 1: Add useSettings hook for reading multiple settings at once WordPress/gutenberg#55337
- 2: https://make.wordpress.org/core/2024/03/09/miscellaneous-editor-changes-in-wordpress-6-5/
- 3: https://github.com/WordPress/gutenberg/blob/trunk/packages/block-editor/CHANGELOG.md
🏁 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 -50Repository: 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=5Repository: 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 leastheader to6.5, or - Replacing
useSettingswithuseSetting(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.
| // 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]); |
There was a problem hiding this comment.
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.
| 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] | ||
| ); |
There was a problem hiding this comment.
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.
| 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', | ||
| }, | ||
| }, | ||
| ]; |
There was a problem hiding this comment.
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').
…m_gutenberg_block
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
wpuf/post-form(replaces the legacywpuf/wpuf-form-block). Existing posts using the old block will show a block-recovery prompt in the editor.[wpuf_form]shortcode (includes/templates/blocks/post-form.php) — no change to shortcode output, hooks, or filters.WeDevs\Wpuf\Frontend\Form_Gutenberg_Blockhas been removed along with its asset bundle (assets/js/admin/gutenblock.js,assets/css/admin/gutenblock.css,assets/js/admin/blockFrameSetup.js).Breaking Changes
[wpuf_form id="…"]) continues to work unchanged as a fallback.WeDevs\Wpuf\Frontend\Form_Gutenberg_Blockis no longer loaded. Any custom code referencing it should switch toWeDevs\Wpuf\Blocks\PostFormor the shortcode.Summary by CodeRabbit
New Features
Improvements
Deprecations