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 45 minutes and 45 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: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughAdded conditional currency data localization in PHP and implemented single product field handling in the JavaScript form builder, including price formatting utilities and label display logic based on product options. Changes
Sequence DiagramsequenceDiagram
participant Admin as Admin Page
participant Builder as Form Builder JS
participant LocalScript as Localized Currency Data
participant UI as Builder UI
Admin->>LocalScript: Load form builder page
LocalScript->>Builder: Provide frm_admin_js.currency settings
Builder->>Builder: User updates product field
Builder->>Builder: Check if field is single product type
alt Single Product Field
Builder->>Builder: Get product option label
Builder->>Builder: formatProductPrice() with currency data
Builder->>UI: updateSingleProductLabel(label + price)
UI->>UI: Display formatted product with price
else Standard Field
Builder->>UI: Render normal option updates
end
Builder->>Builder: adjustConditionalLogicOptionOrders()
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 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 |
|
|
Overall Grade |
Security Reliability Complexity Hygiene |
Code Review Summary
| Analyzer | Status | Updated (UTC) | Details |
|---|---|---|---|
| PHP | Apr 20, 2026 5:51p.m. | Review ↗ | |
| JavaScript | Apr 20, 2026 5:51p.m. | Review ↗ |
Important
AI Review is run only on demand for your team. We're only showing results of static analysis review right now. To trigger AI Review, comment @deepsourcebot review on this thread.
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@js/src/admin/admin.js`:
- Around line 6219-6220: The preview concatenation can produce "undefined"
because currency.symbol_padding may be missing; update the places building
leftSymbol and rightSymbol (the expressions referencing currency.symbol_left,
currency.symbol_right and currency.symbol_padding) to default symbol_padding to
an empty string (e.g., use currency.symbol_padding ?? '' or equivalent) before
concatenation so missing padding won't render "undefined".
- Around line 6244-6271: In updateSingleProductLabel, after you read price from
optWrapper, also locate the hidden product input inside optWrapper (e.g., const
hiddenInput = optWrapper.querySelector('input[type="hidden"][data-frmprice]') )
and update its stored price so live calculations use the new value; set
hiddenInput.dataset.frmprice = price and hiddenInput.value = price (guarding for
hiddenInput existence) before updating labelEl.innerHTML so both the visible
label and the hidden price attribute stay in sync.
🪄 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: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 36a7eb9a-5e98-45bb-af86-1fdab09b5fa2
📒 Files selected for processing (3)
classes/helpers/FrmAppHelper.phpjs/formidable_admin.jsjs/src/admin/admin.js
| const leftSymbol = currency.symbol_left ? ( currency.symbol_left + currency.symbol_padding ) : ''; | ||
| const rightSymbol = currency.symbol_right ? ( currency.symbol_padding + currency.symbol_right ) : ''; |
There was a problem hiding this comment.
Default symbol_padding before concatenating it.
If localized currency data is missing symbol_padding, the preview can render undefined next to the symbol.
Proposed fix
- const leftSymbol = currency.symbol_left ? ( currency.symbol_left + currency.symbol_padding ) : '';
- const rightSymbol = currency.symbol_right ? ( currency.symbol_padding + currency.symbol_right ) : '';
+ const symbolPadding = currency.symbol_padding ?? '';
+ const leftSymbol = currency.symbol_left ? ( currency.symbol_left + symbolPadding ) : '';
+ const rightSymbol = currency.symbol_right ? ( symbolPadding + currency.symbol_right ) : '';📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const leftSymbol = currency.symbol_left ? ( currency.symbol_left + currency.symbol_padding ) : ''; | |
| const rightSymbol = currency.symbol_right ? ( currency.symbol_padding + currency.symbol_right ) : ''; | |
| const symbolPadding = currency.symbol_padding ?? ''; | |
| const leftSymbol = currency.symbol_left ? ( currency.symbol_left + symbolPadding ) : ''; | |
| const rightSymbol = currency.symbol_right ? ( symbolPadding + currency.symbol_right ) : ''; |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@js/src/admin/admin.js` around lines 6219 - 6220, The preview concatenation
can produce "undefined" because currency.symbol_padding may be missing; update
the places building leftSymbol and rightSymbol (the expressions referencing
currency.symbol_left, currency.symbol_right and currency.symbol_padding) to
default symbol_padding to an empty string (e.g., use currency.symbol_padding ??
'' or equivalent) before concatenation so missing padding won't render
"undefined".
| function updateSingleProductLabel( fieldId ) { | ||
| const labelEl = document.querySelector( `#field_${ fieldId }_inner_container .frm_single_product_label` ); | ||
| if ( ! labelEl ) { | ||
| return; | ||
| } | ||
|
|
||
| const firstRealOpt = document.querySelector( `#frm_field_${ fieldId }_opts .frm_single_option:not(.frm_option_template)` ); | ||
| if ( ! firstRealOpt ) { | ||
| return; | ||
| } | ||
|
|
||
| const firstOptKey = firstRealOpt.dataset.optkey; | ||
| const optWrapper = document.getElementById( `frm_delete_field_${ fieldId }-${ firstOptKey }_container` ); | ||
| if ( ! optWrapper ) { | ||
| return; | ||
| } | ||
|
|
||
| const label = optWrapper.querySelector( `.field_${ fieldId }_option` )?.value ?? ''; | ||
| const price = optWrapper.querySelector( '.frm_product_price' )?.value ?? ''; | ||
|
|
||
| const parts = []; | ||
| if ( label ) { | ||
| parts.push( label ); | ||
| } | ||
| if ( price ) { | ||
| parts.push( formatProductPrice( price ) ); | ||
| } | ||
| labelEl.innerHTML = purifyHtml( parts.join( ': ' ) ); |
There was a problem hiding this comment.
Update the hidden product input along with the label.
The single-product template carries the selected product price on the hidden input as data-frmprice (classes/views/frm-fields/front-end/product-single.php:35). This path updates only the visible label, so live totals/calculations can keep reading a stale hidden input price after a builder price edit.
Proposed fix
function updateSingleProductLabel( fieldId ) {
const labelEl = document.querySelector( `#field_${ fieldId }_inner_container .frm_single_product_label` );
if ( ! labelEl ) {
return;
}
- const firstRealOpt = document.querySelector( `#frm_field_${ fieldId }_opts .frm_single_option:not(.frm_option_template)` );
- if ( ! firstRealOpt ) {
- return;
- }
-
- const firstOptKey = firstRealOpt.dataset.optkey;
- const optWrapper = document.getElementById( `frm_delete_field_${ fieldId }-${ firstOptKey }_container` );
- if ( ! optWrapper ) {
+ const firstOpt = getMultipleOpts( fieldId )[ 0 ];
+ if ( ! firstOpt ) {
return;
}
- const label = optWrapper.querySelector( `.field_${ fieldId }_option` )?.value ?? '';
- const price = optWrapper.querySelector( '.frm_product_price' )?.value ?? '';
-
const parts = [];
- if ( label ) {
- parts.push( label );
+ if ( firstOpt.label ) {
+ parts.push( firstOpt.label );
}
- if ( price ) {
- parts.push( formatProductPrice( price ) );
+ if ( firstOpt.price ) {
+ parts.push( formatProductPrice( firstOpt.price ) );
}
labelEl.innerHTML = purifyHtml( parts.join( ': ' ) );
+
+ const metaInput = document.querySelector( `[name="item_meta[${ fieldId }]"]` );
+ if ( metaInput ) {
+ metaInput.value = firstOpt.saved;
+ metaInput.dataset.frmprice = firstOpt.price || '';
+ }
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| function updateSingleProductLabel( fieldId ) { | |
| const labelEl = document.querySelector( `#field_${ fieldId }_inner_container .frm_single_product_label` ); | |
| if ( ! labelEl ) { | |
| return; | |
| } | |
| const firstRealOpt = document.querySelector( `#frm_field_${ fieldId }_opts .frm_single_option:not(.frm_option_template)` ); | |
| if ( ! firstRealOpt ) { | |
| return; | |
| } | |
| const firstOptKey = firstRealOpt.dataset.optkey; | |
| const optWrapper = document.getElementById( `frm_delete_field_${ fieldId }-${ firstOptKey }_container` ); | |
| if ( ! optWrapper ) { | |
| return; | |
| } | |
| const label = optWrapper.querySelector( `.field_${ fieldId }_option` )?.value ?? ''; | |
| const price = optWrapper.querySelector( '.frm_product_price' )?.value ?? ''; | |
| const parts = []; | |
| if ( label ) { | |
| parts.push( label ); | |
| } | |
| if ( price ) { | |
| parts.push( formatProductPrice( price ) ); | |
| } | |
| labelEl.innerHTML = purifyHtml( parts.join( ': ' ) ); | |
| function updateSingleProductLabel( fieldId ) { | |
| const labelEl = document.querySelector( `#field_${ fieldId }_inner_container .frm_single_product_label` ); | |
| if ( ! labelEl ) { | |
| return; | |
| } | |
| const firstOpt = getMultipleOpts( fieldId )[ 0 ]; | |
| if ( ! firstOpt ) { | |
| return; | |
| } | |
| const parts = []; | |
| if ( firstOpt.label ) { | |
| parts.push( firstOpt.label ); | |
| } | |
| if ( firstOpt.price ) { | |
| parts.push( formatProductPrice( firstOpt.price ) ); | |
| } | |
| labelEl.innerHTML = purifyHtml( parts.join( ': ' ) ); | |
| const metaInput = document.querySelector( `[name="item_meta[${ fieldId }]"]` ); | |
| if ( metaInput ) { | |
| metaInput.value = firstOpt.saved; | |
| metaInput.dataset.frmprice = firstOpt.price || ''; | |
| } | |
| } |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@js/src/admin/admin.js` around lines 6244 - 6271, In updateSingleProductLabel,
after you read price from optWrapper, also locate the hidden product input
inside optWrapper (e.g., const hiddenInput =
optWrapper.querySelector('input[type="hidden"][data-frmprice]') ) and update its
stored price so live calculations use the new value; set
hiddenInput.dataset.frmprice = price and hiddenInput.value = price (guarding for
hiddenInput existence) before updating labelEl.innerHTML so both the visible
label and the hidden price attribute stay in sync.
Fixes https://github.com/Strategy11/formidable-pro/issues/6416
Before: See the issue.
After:
Screen.Recording.2026-04-21.at.00.36.33.mov
Summary by CodeRabbit
New Features
Improvements