Storefront fields and pricing

The product form shows the current server-resolved group definitions. The browser submits field and option identifiers, but it does not decide labels, availability, or prices. POM Tweaks resolves those values again before adding the product to the cart.

Optional visual controls and mobile flow

Text, color, and image swatches are presentation modes for the existing radio or checkbox inputs. Selecting a swatch checks that native input; there is no second stored value or browser-owned price. Without CSS, the input and its full label remain normal form controls. With CSS, each target is at least 44 pixels high, selected, disabled, hover, and keyboard-focus states remain visible, and labels wrap instead of creating a horizontal scroll trap.

Image swatches use the selected WordPress attachment size with intrinsic width and height, responsive srcset and sizes, lazy loading, and asynchronous decoding. The visible option label remains beside every image, including when an image fails to load. Configure alternative text only for meaningful image content; leave it empty when it would merely repeat that label. POM primes the attachment posts and metadata for all resolved option images before rendering instead of querying media one option at a time.

An administrator can independently opt a group into a native collapsible disclosure or a JavaScript-enhanced step. A required-field or server-guidance error opens the corresponding disclosure and activates its step before focus moves to the field. With JavaScript disabled, all step groups remain expanded, and native collapsible groups still work.

The optional selection summary lists current non-empty fields and the same displayed options delta emitted by the normal totals calculator. Its live region announces only the changing total, not every character typed into a text field. Sticky mode activates through a container query only when the product-form area is wide enough; narrow product columns and mobile layouts keep it in normal document flow.

The extra visual stylesheet and script load only when a resolved group uses a swatch, disclosure, step, or summary. An archive loads them when its Quick View provider explicitly runs wc_quick_view_enqueue_scripts, because the product configuration is not known until the modal response arrives. Products using only the default controls keep the existing storefront payload.

Apply and share selected fields through the product URL

Enable Push changes to URL on an individual add-on field when that field may be represented in a public product URL. The same opt-in controls both directions: the canonical single-product page reads the parameter when it opens, and later customer changes replace that parameter in the current address without reloading the page or adding one browser-history entry per change.

POM Tweaks assigns and displays a stable parameter such as addon-gift-wrap-a1b2c3d4 after the field has been saved. The readable part comes from the original field title, while the UUID fragment prevents assigned groups from claiming the same parameter. Choice values use current option UUIDs, checkbox selections use comma-separated UUIDs, and text, date, multiplier, and customer-price controls use their normalized entered value. The reserved value ~ means that the field is deliberately empty, so clearing a default or preset value remains empty after a reload. Copy the resulting browser address after configuring the product rather than constructing option UUIDs manually.

An incoming URL is only a prefill. Current field conditions, required state, option availability, numeric and text limits, product or variation price, tax, and add-on price are resolved again. Unknown or unavailable option UUIDs are not selected, and the normal nonce-protected add-to-cart parser validates the final form. A URL therefore cannot preserve an old price or authorize an unavailable option.

File fields and headings cannot enable this setting. For other text-like fields, remember that URL values may be retained by browser history, analytics tools, reverse proxies, and server logs. Do not enable the setting for names, contact details, instructions, or other sensitive values unless that exposure is appropriate for the site. Each decoded URL value is bounded to 4 KB. A product page that exposes an opted-in field sends no-referrer; when the request already contains one of its recognized parameters, it also sends no-cache directives. This keeps WordPress-aware caches and outbound referrers from replaying or propagating the configured value.

When an enabled Product Add-On belongs to a selected POM Composite component, its parameter also includes that chapter and component identity. This keeps two selected products that reuse the same add-on group from overwriting each other. Deselecting the component removes its loaded add-on parameters from the current address. Quick View forms do not update an archive URL because that URL would not identify one canonical product page.

Price types

  • Flat fee adds the configured amount once to the cart line, regardless of its quantity.
  • Quantity based adds the configured amount to every unit of the product.
  • Percentage based calculates the percentage from the product's base unit price and applies it to every unit.
  • Custom price always uses the customer's accepted amount as a quantity-based price.
  • Input multiplier multiplies the configured amount or percentage first, then applies its selected price type.

Which price type should you choose?

Choose Calculation Example with quantity 3 Best for Do not choose it when
Flat fee The configured amount is added once to the cart line. A 5.00 gift-wrapping option adds 5.00. One service, setup, handling, or packaging charge per configured line. Every purchased unit needs its own charge.
Quantity based The configured amount is multiplied by the WooCommerce line quantity. A 5.00 engraving charge adds 15.00. Per-unit materials, personalization, licenses, or services. The charge should remain once for the complete line.
Percentage based The configured percentage is applied to the authoritative base unit price, then multiplied by line quantity. A 10% option on a 40.00 product adds 12.00. Proportional insurance, premium finish, or service levels that should follow the product or variation price. The customer expects one fixed monetary amount, or the base price can vary in a way the business does not want reflected.

Customer-defined price is a field type, not a fourth Price type. The accepted customer amount behaves as quantity-based pricing. Quantity multiplier is also a field type: its entered whole number multiplies the configured rate before the selected price-type rule is applied.

For variable products, the selected variation supplies the authoritative base price. The product page shows lightweight Options total and Estimated total feedback while the customer makes a selection. The WooCommerce cart calculation remains authoritative and applies the store's normal tax and total rules.

When Country pricing zones is active, every fixed monetary policy can optionally provide an amount for each enabled zone. This includes fixed option values, flat fees, quantity amounts, reusable-choice prices, tier amounts, and custom-price minimum and maximum values. Leave a zone input empty to inherit the ordinary global amount. Percentage values remain one global percentage and calculate from the authoritative regional product or booking base.

Temporarily disabling Country pricing zones, disabling one zone, or making its configuration unavailable hides the corresponding regional controls but does not erase their saved overrides during an unrelated Product Add-On edit. Re-enable the valid zone to review or clear its visible values deliberately.

The product form receives only the already resolved zone values and a bounded applied-context identifier. It never receives the private map of all zone amounts. Cacheable single-product HTML contains the neutral form marker; the private product-action response inserts the complete regionalized form and initializes POM Product Add-Ons once.

Configure economic policies

Open a Product Add-On group or a product's Add-Ons tab, expand Economic policy for a priced field or option, and choose only the policies that the store needs. Existing definitions normalize to Current behavior, Discount add-on price with eligible coupons, product tax inheritance, and disabled tier pricing, so upgrading does not change their totals.

Tier pricing selects a rate from non-overlapping inclusive intervals. Use WooCommerce product quantity for ordinary fields and options. An Input multiplier field can instead use its entered value to select the interval; the selected tier rate is then multiplied by that entered value. A quantity outside every interval uses the normal add-on price. Customer-entered custom prices cannot enable tiers.

Coupon policy is evaluated only after WooCommerce confirms that the coupon can discount the product. Exclude add-on price from coupon discounts protects that add-on contribution while WooCommerce continues to own coupon product rules, usage limits, allocation, and sequential application. This works for percentage, fixed-product, and fixed-cart coupons without turning the add-on into a fee.

Every add-on increment inherits the product's tax status and tax class. This is fixed because the increment belongs to the same WooCommerce line: assigning another class would require a separate line or fee and would no longer match Product Add-Ons cart, order, refund, and API behavior.

Subscription charge policies are available only as an opt-in behavior:

  • Current behavior (all purchases) preserves the existing result for ordinary purchases and every subscription phase.
  • Subscription initial payment only contributes to the initial or switch payment, but not recurring carts or renewals.
  • Subscription initial and recurring payments contributes to the first subscription payment and later recurring payments and renewals.
  • One-time purchase only contributes when the product is bought without a subscription plan. It does not contribute when a fixed subscription product or an All Products for WooCommerce Subscriptions plan is selected.

WooCommerce Subscriptions remains responsible for proration, sign-up fees, trials, switches, renewal creation, and changes of quantity. The accepted policy and resolved result are saved in the line snapshot, so completed order history is not recalculated from a later definition. Order again remains a new purchase and uses the current policy.

Calculation order

The same order is used by the product preview, classic cart, Store API, order creation, subscriptions, and Bookings:

Order Operation Result
1 Resolve product or variation and accepted customer value Establishes the authoritative base price, quantity, and selection.
2 Select a tier Chooses the matching rate from product quantity or multiplier input; gaps use the configured add-on rate.
3 Apply input and Bookings multipliers Multiplies the selected rate by the entered multiplier, then by enabled person/block units. Flat fees ignore Bookings units.
4 Apply the add-on price type Percentage uses the authoritative base; quantity-based uses the line quantity; flat fee applies once to the line.
5 Apply subscription phase Removes contributions that do not belong to the current one-time, initial, switch, recurring, or renewal context.
6 Build the WooCommerce product line Adds the accepted contribution to the product line at WooCommerce calculation precision.
7 Apply coupons WooCommerce evaluates eligibility and limits; protected add-on contributions are removed from its discountable amount.
8 Apply product tax and final currency rounding WooCommerce uses the product tax status/class and rounds at the active currency boundary.

All Products for WooCommerce Subscriptions plan pricing runs through its existing add-on discount decision during the line-price stage. Currency and dynamic-pricing integrations can filter a resolved server rate with pom_tweaks_product_addons_resolved_rate; the callback receives the normalized policy, tier quantity, charge context, field/option UUID, and currency. A matching browser integration must update the preview separately because PHP never makes a browser-supplied rate authoritative. pom_tweaks_product_addons_charge_context can adapt a verified server cart phase, pom_tweaks_product_addons_order_charge_context can adapt the phase for an editable order line, and pom_tweaks_product_addons_coupon_discount_amount can adjust the already bounded coupon result without bypassing WooCommerce coupon eligibility.

Choose when the estimated total appears

Go to WooCommerce → Settings → Products → Add-ons. Leave Show incomplete subtotal disabled to hide both running totals until every required add-on field is valid and a variation has been selected. Enable it when customers should see the running estimate while required fields are still incomplete.

This preference uses the same setting as WooCommerce Product Add-Ons, so switching between the official extension and the POM storefront does not reset it. The woocommerce_product_addons_show_grand_total filter can still remove the complete totals region for a product.

The totals region uses a polite live announcement and updates in one browser animation frame when several input events occur together. It does not make a pricing request on every keystroke. The server independently resolves and prices the submitted configuration before it reaches the cart.

After each calculation, the product form emits the native pom-pao-totals-updated event and the official-compatible jQuery updated_addons event. The detail includes visibility, quantity, raw and displayed option totals, raw and displayed estimated totals, booking state, and taxable state. Optional Bookings and subscription integrations feed their accepted contexts into this same calculator; neither extension is required for ordinary products.

Taxes, localized amounts, and price suffixes

The preview follows the WooCommerce product-page display context rather than assuming that stored and displayed prices are identical:

  • Prices entered including tax are converted before add-on amounts are displayed excluding tax.
  • Prices entered excluding tax are increased when the shop displays product prices including tax.
  • Tax-exempt customers receive the same exempt display used by WooCommerce.
  • Taxable products include the configured WooCommerce price suffix, including its {price_including_tax} and {price_excluding_tax} replacements. Non-taxable products do not show a tax suffix.
  • A zero-priced product still receives a neutral tax conversion for flat, quantity-based, and custom add-on amounts.

Custom-price fields accept the current WooCommerce decimal separator. For example, a store using a comma can accept 1,50; the server normalizes that value before validating its configured minimum and maximum. Product quantity and input-multiplier fields remain whole-number controls where their field contract requires it.

The preview calculates raw and display totals separately. Flat fees are added once per cart line, quantity and custom prices are multiplied by the product quantity, and percentage prices use the selected product or variation base price. This avoids deriving tax from an already rounded visible amount.

Monetary precision and rounding

POM Product Add-Ons follows WooCommerce's active currency precision and its higher internal calculation precision. Configured prices, accepted custom prices, and saved selection snapshots use canonical decimal values. Percentage, multiplier, quantity, subscription, and booking calculations are normalized at WooCommerce calculation precision before tax, coupon, cart, or order APIs receive them. Customer-facing and final order amounts are rounded at the currency boundary, so currencies with zero, two, or three decimal places retain their expected WooCommerce behavior.

The browser preview uses scaled monetary units at the same internal precision. This prevents common binary artifacts such as 0.1 + 0.2 from appearing in the estimate, but it does not make the browser authoritative. The server reloads the current product and add-on prices and performs the complete calculation again. Negative configured adjustments continue to work where the field definition permits them; customer-entered custom prices remain non-negative.

Stores that allow fractional product quantities keep those positive quantities for quantity-based and percentage add-ons. Flat fees still apply once to the line. Input multipliers remain whole numbers because that is the field's validation contract.

When a flat fee must pass through WooCommerce's unit-price API, POM retains a bounded set of allocation digits. For example, a 0.10 line fee divided across three units is carried as a unit bridge and recomposes to exactly 0.10 before WooCommerce calculates the line, coupon, and tax totals. Those guard digits are internal and customer-facing values still use the active currency decimals.

Subscription product pricing

WooCommerce Subscriptions and All Products for WooCommerce Subscriptions remain optional. When either extension is active, the Product Add-Ons preview follows the selected one-time or subscription plan and keeps WooCommerce's recurring interval, trial, and sign-up-fee details beside the estimated total.

All Products for WooCommerce Subscriptions decides whether a plan discount applies to add-ons. POM Tweaks follows its wcsatt_discount_addons decision:

  • Discount and fixed-discount plans apply their price rule to add-ons when the extension allows it.
  • Override-price plans protect add-ons from the plan price by default, so the override replaces the product base price and the add-ons remain additional charges.
  • Percentage-based add-ons continue to use the effective plan base price.
  • A flat fee remains one line-level amount instead of becoming a per-unit recurring amount.

The same decision is applied in the product preview, classic cart, Cart and Checkout Blocks, order metadata, and server totals. The browser only displays the selected plan result; WooCommerce and the subscription extension remain authoritative.

Price booking products

WooCommerce Bookings and Accommodation Bookings remain optional. When either product type is used, Bookings first validates the date, resource, duration, people, availability, and current booking cost. POM Product Add-Ons then applies its configured prices to that accepted booking cost:

  • Multiply cost by person count uses the total across all selected person types.
  • Multiply cost by block or night count uses the accepted customer-selected duration.
  • Selecting both multiplies a quantity-based amount or percentage by both counts.
  • A percentage is calculated from the complete current booking cost, including the selected date and resource rules.
  • A flat fee is still charged once and ignores both multiplier settings.
  • The ordinary WooCommerce cart quantity is not applied again to booking add-ons.

The preview recalculates after Bookings changes the date, resource, duration, people, or raw booking cost. It uses the same tax display mode as Bookings, while the server recalculates the complete amount independently before accepting the cart line. Existing Accommodation Bookings configurations using its older night-multiplier setting continue to behave as the current block multiplier.

Validation behavior

The product form validates each field after the customer interacts with it and validates the complete add-on form when Add to cart is used. It does not announce errors while an untouched form is loading. An invalid field receives a nearby message, aria-invalid, and an accessible description relationship. The optional error summary links to every invalid field, while keyboard focus moves directly to the first control that needs attention.

Checkbox and image-choice sets are treated as one semantic fieldset, so a required set is valid when at least one available choice is checked. The same client guidance covers radio buttons, selects, text and textarea length, letters/numbers/alphanumeric/email restrictions, localized non-negative custom prices, whole-number multipliers, configured numeric limits, dates, and required files. If a selected reusable choice becomes unavailable after a variation or availability update, the form clears that stale selection, explains the change, and requires a new valid choice.

The summary is enabled by default. Developers can remove only that summary with pom_tweaks_product_addons_show_validation_summary; per-field messages and server validation remain active.

POM Tweaks repeats every rule on the server: required fields, permitted option identifiers, disabled choices, text length and content restrictions, numeric limits, whole-number multipliers, non-negative custom prices, and valid calendar dates. Browser changes therefore cannot approve a value, UUID, availability state, or price that PHP rejects.

When a classic add-to-cart request fails, nonce-verified text, textarea, date, number, select, radio, and checkbox values are shown again so the customer can correct only the invalid field. Defaults are not silently reapplied over that submitted configuration. File inputs are the deliberate exception because browser security does not allow a site to restore a newly selected local file; the customer must select that local file again. A previously uploaded file loaded from the current cart session remains available until the customer clears or replaces it.

Dates and file uploads

Date fields use the browser's native date control, so current Chrome and Safari present the picker in the visitor's language while submitting one unambiguous ISO calendar value. POM validates that exact YYYY-MM-DD value and formats it with the WordPress site date format for cart and order display. It calculates compatibility timestamps at noon in the store timezone, which keeps dates stable across daylight-saving changes and supports years before 1970. The official woocommerce_pao_date_input_timezone_reference filter accepts default for the visitor offset or store for the store offset; neither setting changes the selected calendar day.

The Clear control removes the date without requiring a mouse. A selected file displays its name and formatted size beside the input, and Clear removes that new browser selection. File uploads are checked against PHP and WordPress upload errors, the real temporary-file size, the WordPress and multisite size ceiling, the permitted extension, and the MIME type detected from the file contents. Double extensions containing executable or active-content types are rejected even when their final extension looks allowed.

Accepted files receive an opaque identifier and are stored outside the public web root by default. Cart and order screens generate expiring download links; the download controller then verifies the signature and the current cart session, order ownership, guest order key, or WooCommerce management capability before returning any bytes. A file identifier or old URL by itself never grants access, and unauthorized or missing requests receive the same non-enumerable response.

Opening a configured item from the cart displays the existing upload as a link outside the file input. The browser sends only a keep-or-clear choice; POM retrieves the opaque identifier from that cart session and never trusts a hidden browser URL or path. Selecting a replacement file supersedes the previous upload after the cart or order update succeeds. Clearing a required existing upload makes a new file mandatory. The order-line editor follows the same rule under Saved selections and never attempts to populate input.files.

Custom Store API clients cannot send a file body inside the JSON add-to-cart extension. First send a multipart file request to POST /wp-json/pom-tweaks/v1/product-addons/files with a valid WordPress REST nonce, Store API nonce, or the current Store API Cart-Token. A headless client should send the same Cart-Token to this upload and the subsequent cart request so both operations resolve one cart owner. The response contains a file_id, sanitized name, detected MIME type, and size, but no public URL. Submit that file_id as the file field value in the normal add-to-cart request. POM verifies that the identifier belongs to the same WooCommerce session and repeats the field-specific extension and size checks. Arbitrary HTTP URLs are rejected.

Temporary uploads that never reach an accepted cart line expire after one day. Active cart uploads expire after seven days unless the cart session refreshes them. Order files remain with the order and are removed when the last linked order is permanently deleted or when WooCommerce removes that order's personal data. Cleanup runs in small daily batches under an expiring lock; a failed replacement therefore cannot delete the previously accepted file and its unused replacement is removed later.

The default local store must remain outside the public document root and must be included in backups together with the database. A media-offload integration can implement pom_tweaks_product_addons_store_file, pom_tweaks_product_addons_download_file, and pom_tweaks_product_addons_delete_file; the three callbacks must use the opaque storage key and must never return an unrestricted permanent URL. pom_tweaks_product_addons_private_upload_directory may relocate local storage to another non-public directory. Test restore and deletion before enabling an adapter in production.

Older POM and official Product Add-Ons snapshots are migrated lazily when an authorized cart or order view needs the file. POM copies the known local legacy file into private storage and keeps the original metadata and source file untouched for rollback. Apache and IIS deny files are added to known legacy upload directories where writable. Nginx and other servers that ignore those files must deny direct HTTP access to the legacy Product Add-Ons upload locations at the hosting layer. After representative historical orders download correctly and a synchronized database/private-file backup exists, the old files can be archived or removed through a controlled hosting maintenance operation; POM does not bulk-delete them automatically.

Quick View compatibility

POM Product Add-Ons supports both WooCommerce Quick View and the POM Theme product Quick View without requiring either provider.

  • WooCommerce Quick View asks integrations to enqueue their archive assets through wc_quick_view_enqueue_scripts. POM Tweaks responds only to that request, then initializes each add-on form inserted by AJAX. It also supports the provider's quick-view-displayed browser event.
  • POM Theme opens the normal product URL in an isolated Quick View frame. The product page therefore loads its own add-on assets inside that frame; the surrounding shop archive does not receive an unnecessary copy.
  • Forms inserted after page load are initialized once. Removing a modal also removes its Product Add-Ons listeners, variation handlers, pending total update, and availability observer before a later product is opened.
  • Each open product keeps its own form, nonce, UUID values, validation state, upload control, variation price, and subtotal context. Values from a closed modal are not reused by the next one.

A custom AJAX Quick View integration should run the WordPress wc_quick_view_enqueue_scripts action on archive requests and trigger quick-view-displayed on document.body after inserting the product form. The event may pass the inserted element or jQuery object as its second argument. POM Tweaks also detects inserted forms while its conditionally loaded script is present, but the official enqueue action remains necessary so an archive does not have to load Product Add-Ons globally.

Cart and order result

Each accepted value is displayed below its cart line. Selections with different values remain distinct cart configurations. The order preserves the accepted customer-facing values so historical details do not depend on later label or price edits.

Changing or disabling a reusable choice affects new submissions, restored cart sessions, and products added through Order again. It does not rewrite completed orders.

Verification

  1. Add a product with a fixed quantity-based option and set the cart quantity to two. Confirm the option amount is charged twice.
  2. Add a flat-fee option, raise the quantity, and confirm that fee remains charged once for the line.
  3. Add a percentage option and confirm it follows the selected product or variation base price.
  4. Add tiers 1–2, 3–5, and 6+, change the line quantity across every boundary, and confirm an uncovered quantity uses the configured fallback rate.
  5. Apply a percentage, fixed-product, and fixed-cart coupon to a line containing one discountable and one protected option; confirm only the permitted amount is discounted.
  6. Repeat with shop prices including and excluding tax and confirm the complete increment inherits the product tax class.
  7. If Subscriptions is active, place initial, recurring, renewal, and switch calculations with initial-only and recurring policies. If All Products for WooCommerce Subscriptions is active, repeat with its one-time plan selected.
  8. Submit each required field empty and confirm the first invalid control receives focus, every invalid field exposes aria-invalid and a nearby message, and the summary links back to each control.
  9. Try an unavailable reusable choice by altering the submitted option identifier and confirm the server rejects it.
  10. If uploads are enabled, select one allowed file and confirm its name and size appear. Clear it, then try an oversized file, false MIME, double active extension, renamed file, and disallowed type; confirm the field-level and server messages identify the upload field.
  11. Complete a test order and confirm each accepted value appears in the order line metadata.
  12. On a booking product, select two blocks and three people. Confirm person, block, combined percentage, and flat-fee fields update the preview, then confirm the cart total matches it.
  13. On a native subscription product, select add-ons and confirm the estimated total retains the recurring interval details.
  14. On an All Products for WooCommerce Subscriptions product, compare one discount plan and one override-price plan. Confirm add-ons receive or avoid the plan adjustment according to the configured WCS_ATT policy.
  15. Leave Show incomplete subtotal disabled, clear a required field, and confirm the totals region is hidden. Enable the setting and confirm the running estimate remains visible for the same incomplete form.
  16. Test prices entered including and excluding tax against both shop display modes. Repeat with a tax-exempt customer and confirm the preview follows the WooCommerce product price in every case.
  17. On a zero-priced product, combine a flat fee, quantity-based price, percentage, localized custom price, product quantity greater than one, and an input multiplier. Confirm the preview and accepted cart line agree.
  18. With only the keyboard, correct a required checkbox set, restricted text, custom price, multiplier, date, and file field. Confirm errors appear only after interaction or submit and disappear as each value becomes valid.
  19. Cause a server rejection after completing several valid fields. Confirm the page preserves every posted value except the local file selection and does not restore field defaults over the submitted configuration.
  20. Disable a selected reusable choice through a variation or availability integration and emit pom-pao-availability-changed on the product form. Confirm the stale value is cleared and the field is revalidated.
  21. Open a simple product with add-ons through Quick View, select values, add it to the cart, close the modal, and repeat with a different product. Confirm the second form has independent values, UUIDs, nonce, subtotal, and validation state.
  22. Repeat Quick View with a variable product, including a default variation, variation changes, an image choice, and an upload field. Confirm the selected variation updates the preview and the accepted cart line contains the same configuration.
  23. Open and close the same Quick View several times. Confirm one Product Add-Ons calculation and one add-to-cart request occur per interaction, then confirm a page without a product Quick View provider does not load the Product Add-Ons stylesheet or script.
  24. In Spanish and English on current Chrome and Safari, select and clear an ordinary date, a date across a daylight-saving boundary, and a date before 1970. Confirm the ISO value and the formatted cart and order day remain identical.
  25. Open a cart item with an existing upload. Keep it without reselecting a file, replace it, then clear it. Confirm required validation appears only after the existing upload is cleared and that no file input is ever pre-populated.
  26. Combine prices 0.1 and 0.2, a percentage, a multiplier, quantity greater than one, tax, and a coupon. Confirm the preview, cart, order metadata, and order REST response contain normalized decimal amounts without long binary residues.
  27. Repeat the monetary check with currencies configured for zero, two, and three decimal places. Confirm display and order totals use the active currency decimals while Store API raw prices retain WooCommerce's higher calculation precision.
  28. Complete an upload as a guest. Confirm the same session can download it from the cart, a different browser receives the generic unavailable response, the guest order link works with its order key, and an authorized WooCommerce administrator can download it.
  29. Create an unused temporary upload, an abandoned cart upload, and a failed replacement. Advance their filtered TTLs in staging, run the scheduled cleanup, and confirm only expired unreferenced files are removed.
  30. Compare a default field with text, color, and image swatches with the optional stylesheet enabled and blocked. Confirm every case submits the same UUID-backed radio or checkbox values.
  31. With keyboard only, move through swatches, disabled options, a collapsed required group, and a multi-group step flow. Submit an incomplete step and confirm its disclosure opens before the invalid control receives focus.
  32. Enable the selection summary in a narrow and wide product container. Confirm sticky mode activates only in the wide container, the options delta matches Options total, and typing does not announce the complete summary repeatedly.
  33. Repeat the visual checks in Storefront, POM Theme, a Bootstrap theme, Quick View, and a variable product. Disable JavaScript and confirm every step is expanded and add-to-cart remains usable.
  34. Enable Push changes to URL on a select, checkbox, text, date, multiplier, and custom-price field. Change and clear each value, reload the copied URL, and confirm the same current values return while the reserved ~ value clears defaults.
  35. Alter an option UUID in the URL, disable the selected option, and change its price. Confirm the invalid selection is not applied and the accepted cart line always uses the current server price.
  36. Enable the setting on a conditional field, make it inactive, and confirm its URL value becomes empty and cannot contribute a required value, price, cart value, or order value while inactive.
  37. Confirm file and heading fields cannot enable URL synchronization, Quick View does not rewrite its archive URL, and an enabled component add-on receives a distinct contextual parameter for each selected Composite component. Inspect the response headers with and without a recognized parameter: both product responses use no-referrer, while only the configured request receives no-cache directives.
  38. Save one field, option, tier, and reusable choice with regional values. Temporarily disable Country pricing zones, edit an unrelated label, save, then re-enable the zones and confirm every regional value remains present. Clear one visible zone value and confirm only that deliberate override is removed.

Troubleshooting and rollback

  • If uploads report that private storage is unavailable, ask the host to provide a writable directory outside the public document root or configure a supported offload adapter. Do not fall back to a publicly addressable directory.

  • If a legacy URL remains directly reachable on Nginx or another non-Apache server, add a hosting rule that denies the legacy Product Add-Ons upload locations before migrating historical orders.

  • Rollback does not require changing order snapshots: disable the new storage adapter or restore the database and private-file backup from the same recovery point. Keep legacy source files until historical download verification is complete.

  • If fields do not appear, confirm the product matches the group's scope and the group is enabled.

  • If the official WooCommerce Product Add-Ons extension is active, its storefront takes precedence and the POM Tweaks storefront stays dormant.

  • If a custom theme replaces the classic add-to-cart template without its standard hook, restore the hook or use a compatible product template.

  • If an AJAX Quick View shows fields without behavior, confirm the provider runs wc_quick_view_enqueue_scripts before the archive footer and emits quick-view-displayed after inserting the form. POM Theme's frame-based Quick View does not need that event.

  • If a booking preview does not update, confirm WooCommerce Bookings is active, the product is a booking or accommodation-booking product, and Bookings itself can return a current cost for the selected date and resource.

  • If a subscription preview does not change with the selected plan, confirm the subscription options appear inside the same WooCommerce product form and that the product has a current POM Product Add-Ons definition.

  • To roll back immediately, disable Product Add-Ons under Settings → POM Tweaks. This does not delete groups, reusable choices, or historical order values.

Related: Create groups and reusable choices and cart and order persistence.