Skip to content

PPOM admin save can drop fields when parse_str() exceeds max_input_vars #606

Description

@pirate-bot

Bug Description

Expected: saving a PPOM field group with many customization fields preserves every existing field or returns an error before persisting incomplete data.

Actual: the admin save request serializes all ppom[...] inputs into a single ppom string, then the PHP save handlers decode it with parse_str(). PHP still applies max_input_vars to parse_str(), so large PPOM groups can be truncated before saving. The handler then stores the truncated $product_meta and still returns a success response, which can make many customization fields disappear after clicking Save.

Impact: customers with large PPOM groups can lose field definitions on save, matching the report that nearly 30 customization menus disappeared after saving.

Code reference

  • woocommerce-product-addon/js/admin/ppom-admin.js:134-150 in the submit handler for .ppom-save-fields-meta builds a URLSearchParams string for all ppom[...] field inputs and appends it as one ppom form value.
  • woocommerce-product-addon/inc/admin.php:480-487 in ppom_admin_update_form_meta() decodes $_REQUEST['ppom'] using parse_str() and uses the decoded array as the source for $product_meta.
  • woocommerce-product-addon/inc/admin.php:490-496 filters and JSON-encodes the decoded $product_meta before it is saved.
  • woocommerce-product-addon/inc/admin.php:551-553 persists the_meta with $wpdb->update().

Customer Context

HelpScout conversation: 3316838612.

Customer site: https://gunnystrapsofficial.com/.

Product selected in the ticket: PPOM Pro, with active Essential plans.

Customer report: “I've lost nearly 30 customization menus from my PPOM after I clicked the Save button.” The transcript does not include the Site Health file contents or a field count, but the symptom is consistent with truncation during the PPOM admin save request for a large field group.

Reproduction Notes

Known code-level reproduction:

  1. In a PHP runtime with default max_input_vars=1000, build a query string with many nested ppom[index][key] values.
  2. Run parse_str() on that string.
  3. Observe the warning parse_str(): Input variables exceeded 1000.
  4. Observe that only the variables before the limit are present in the decoded array.
  5. In PPOM, the decoded array is then saved as the_meta, so a large form can reload with fewer customization fields after saving.

Local command result: a generated string with 1,205 PPOM indexes and two values per index produced the PHP warning and decoded only 500 PPOM indexes.

Investigation report

Conclusion

The PPOM admin save path can persist an incomplete field list for large field groups. The current workaround for request-level max_input_vars is incomplete because the server-side parse_str() call is subject to the same variable limit.

A local PHP reproduction using the workspace PHP runtime confirmed the behavior: parsing a query string with 1,205 PPOM field entries emitted parse_str(): Input variables exceeded 1000 and produced only 500 complete PPOM field indexes when each field contributed two leaf variables.

Where this likely occurs

  • woocommerce-product-addon/js/admin/ppom-admin.js:127-150, .ppom-save-fields-meta submit handler: serializes all ppom[...] values into ppomFields and appends the result as formData.append('ppom', ppomFields.toString()).
  • woocommerce-product-addon/inc/admin.php:480-487, ppom_admin_update_form_meta(): checks is_string( $_REQUEST['ppom'] ), runs parse_str( $ppom_encoded, $ppom_decoded ), and replaces $_REQUEST['ppom'] with $ppom_decoded['ppom'].
  • woocommerce-product-addon/inc/admin.php:490-496, ppom_admin_update_form_meta(): filters and encodes the decoded data as $product_meta.
  • woocommerce-product-addon/inc/admin.php:551-553, ppom_admin_update_form_meta(): writes the resulting the_meta value to the PPOM meta table.
  • woocommerce-product-addon/inc/admin.php:301-325, ppom_admin_save_form_meta(): the new-form path has the same initial parse_str() decoding pattern before insert.
  • woocommerce-product-addon/inc/admin.php:381-397, ppom_admin_save_form_meta(): the new-form path decodes again and then updates the_meta through ppom_admin_update_ppom_meta_only().

Engineering considerations

  • The JS comment at woocommerce-product-addon/js/admin/ppom-admin.js:137-140 explicitly identifies max_input_vars as the reason for bundling PPOM fields into one string.
  • PHP’s parse_str() still counts nested query-string leaf variables against max_input_vars; the browser-side bundling only avoids the initial request parser limit for $_POST, not the later decode limit.
  • The save handler has no visible guard comparing the decoded field count with the submitted field count, so truncation can proceed into a successful database update.
  • The database column the_meta is MEDIUMTEXT at woocommerce-product-addon/classes/plugin.class.php:690, so this finding is not centered on the storage column size.

What to verify or explore next

  • Reproduce from the PPOM admin UI with a field group whose serialized ppom[...] leaf inputs exceed the site’s max_input_vars value, then save and compare the field count before and after reload.
  • Check server/PHP logs for parse_str(): Input variables exceeded 1000 around the time of the customer’s save.
  • Confirm whether the affected customer’s field group had enough fields/options/conditions to exceed the default max_input_vars=1000 threshold.

Unknowns / follow-up

  • The customer’s Site Health attachment was referenced in the ticket but not available through the local workspace, so the exact max_input_vars value for the site was not confirmed.
  • The before-save screenshot was referenced in the ticket but not available through the local workspace, so the exact field count and field composition were not confirmed.

Triage Reasoning

Confirmed a product-code defect in the PPOM admin save flow. The save UI attempts to avoid request-level max_input_vars by sending all PPOM fields as one string, but the PHP handler decodes that string with parse_str(), which is itself limited by max_input_vars. A local PHP reproduction showed truncation at the default limit. GitHub issue creation could not be performed in this environment because the gh CLI is not installed.


Source: HelpScout #3316838612
Generated by bug-report-triage workflow (ID: bug-report-triage_69fee99738b0b4.22597556)

Metadata

Metadata

Assignees

No one assigned

    Type

    No fields configured for Bug.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions