Tags: woocommerce/woocommerce
Tags
Fix settings password fields losing characters that look like percent… …-encoded sequences (#63595) * fix(settings): Preserve percent-encoded characters in password fields WordPress's `sanitize_text_field()` strips sequences matching `/%[a-f0-9]{2}/i` as a security measure against URL-encoded HTML injection. This is appropriate for text labels but destroys legitimate characters in passwords — e.g. `NlP4%EcCx}Na` became `NlP4Cx}Na`. Add a dedicated `password` case to the settings save switch that uses `wp_strip_all_tags()` instead of `wc_clean()`. This still strips HTML tags (security) while preserving percent sequences in passwords. Refs WOOPLUG-6157 * test(settings): Move option cleanup to tearDown for failure-safe test isolation Previously, delete_option() calls were at the end of each test body. If an assertion failed, cleanup was skipped, leaving stale options in the database for the remainder of the test run. Also fixes an imprecise assertion message that referenced '%E' instead of the actual '%Ec' sequence in the test password. Refs WOOPLUG-6157 * fix(settings): guard password field sanitization against null raw values Previously, password fields used `wp_strip_all_tags(trim($raw_value))` which coerced null to empty string. When a password field is absent from POST data, $raw_value is null and the save loop should skip it (via the `is_null($value) → continue` check downstream). Without the null guard, a missing field would overwrite the stored password with an empty string. Also removes the redundant outer `trim()` since `wp_strip_all_tags()` already trims internally. Refs WOOPLUG-6157 * chore: add changelog entry for password field percent-encoding fix Refs WOOPLUG-6157 * fix(settings): guard password field sanitization against non-scalar values wp_strip_all_tags() expects a string, but a crafted POST request could send an array value for a password field (e.g. field_name[]=foo), causing a TypeError. Treat non-scalar values the same as null — skip the option update rather than passing them to wp_strip_all_tags(). Mirrors the defensive pattern used by wc_clean() in the default case. Refs WOOPLUG-6157 * test: verify missing password field does not overwrite existing option Add regression test that seeds an option with a known password value, calls save_fields() with data that omits the password field, and asserts the original value is preserved. Refs WOOPLUG-6157 * style: fix equals sign alignment in settings test file Align assignment operators with surrounding statements per PHPCS Generic.Formatting.MultipleStatementAlignment rule. Refs WOOPLUG-6157 * fix(settings): use is_string guard for password field sanitization PHPStan flagged that is_scalar() allows bool|float|int through to wp_strip_all_tags() which expects string. Simplify to is_string() check since POST values are always strings when valid, and treat everything else as null (skip the option update). Refs WOOPLUG-6157 * docs: add pre-push branch lint check to CLAUDE.md Document lint:changes:branch as a required step before pushing. This catches issues like alignment warnings that per-file linting misses, since it compares the full branch diff against trunk. Refs WOOPLUG-6157 * test: fix missing-password test to exercise the correct code path The test_save_fields_does_not_overwrite_missing_password_field test was passing $data = array(), which hit the empty($data) early return at line 925 — the password null guard was never reached. The test passed for the wrong reason. Fix by including a second text field in $data so save_fields enters the foreach loop, while the password key remains absent from POST data. Also add a test for the is_string() array-injection guard, verifying that crafted POST arrays (field[]=foo) are rejected and the existing password value is preserved. Refs WOOPLUG-6157 * fix: use minimal sanitization for password fields to avoid truncation WC_Settings_API::validate_password_field() deliberately uses only trim() + stripslashes() with a comment: "No input sanitization is used to avoid corrupting passwords." The password case added to WC_Admin_Settings::save_fields() used wp_strip_all_tags() instead, which calls PHP's strip_tags() internally. strip_tags() treats a lone '<' as the start of a malformed HTML tag and drops everything from the '<' onward (e.g. "pass<word" becomes "pass"), silently corrupting stored API keys and SMTP passwords. Replace wp_strip_all_tags() with trim( stripslashes() ) to align with the existing WC_Settings_API pattern. The type guard (is_string check) and null-preservation for absent fields remain unchanged. Refs WOOPLUG-6157 * fix: remove redundant stripslashes from password field sanitization save_fields() already calls wp_unslash() on $data values (line 946/949) before the switch statement, which undoes WordPress's magic quotes. The extra stripslashes() in the password case was double-stripping, so a password like "abc\def" would be corrupted to "abcdef". Remove stripslashes() and leave only trim(), since wp_unslash() has already handled the slash removal. Add a test that verifies literal backslashes survive the round-trip (using wp_slash() on test input to simulate WordPress's magic quotes on $_POST data). Refs WOOPLUG-6157 * refactor: shorten password field comment per review feedback Reduce verbosity of the password case comment while keeping all key context: null semantics, why aggressive sanitization is skipped, the wp_unslash() note, and the validate_password_field() reference. Remove brittle line number references. Refs WOOPLUG-6157
[WOOPLUG-6353] add: orphaned fulfillment records when order is deleted ( #63572) * [WOOPLUG-6353] add: orphaned fulfillment records when order is deleted * Delete orphaned fulfillment records when an order is permanently deleted Add delete_by_entity() to FulfillmentsDataStore for hard-deleting fulfillment records and metadata within a transaction. Hook into woocommerce_before_delete_order and before_delete_post via FulfillmentsManager to trigger cleanup on order deletion. * Move validation method docblock to appropriate location * fix: handle errors when deleting fulfillment metadata and records * fix: add missing throws tag * Address PR review feedback for delete_by_entity - Move is_order() check inside try/catch to prevent unhandled exceptions in WordPress hook chain - Change delete_by_entity $entity_id type from int to string for consistency with other datastore methods - Update prepared statement placeholders from %d to %s to match - Add START TRANSACTION failure check with RuntimeException * Use wc_transaction_query for transaction management in delete_by_entity Replace raw $wpdb->query calls with wc_transaction_query() which respects the WC_USE_TRANSACTIONS constant and follows WooCommerce conventions for transaction handling. * Use %s placeholder for entity_id in test SQL queries Match the string-typed entity_id used by the datastore methods by changing %d to %s and integer literals to string literals in test assertion queries. * Update FulfillmentsManagerTest.php Co-authored-by: Fernando Espinosa <Ferdev@users.noreply.github.com> --------- Co-authored-by: Fernando Espinosa <Ferdev@users.noreply.github.com>
Release: Prepare the changelog for 10.6.0-rc.1 (#63600) * Delete changelog files from 10.6.0-rc.1 release * Update the readme files for the 10.6.0-rc.1 release --------- Co-authored-by: woocommercebot <woocommercebot@users.noreply.github.com>
Release: Prepare the changelog for 10.6.0-beta.2 (#63514) * Delete changelog files from 10.6.0-beta.2 release * Update the readme files for the 10.6.0-beta.2 release --------- Co-authored-by: woocommercebot <woocommercebot@users.noreply.github.com>
Release: Prepare the changelog for 10.6.0-beta.1 (#63409) * Delete changelog files from 10.6.0-beta.1 release * Update the readme files for the 10.6.0-beta.1 release --------- Co-authored-by: woocommercebot <woocommercebot@users.noreply.github.com>
Email Editor: Move TemplateSelection to EmailActionsFill slot and exp… …ort for extensibility (#63277) Email Editor: Move TemplateSelection to EmailActionsFill slot Register TemplateSelection via EmailActionsFill using registerPlugin, matching the pattern established for EmailStatus in #63269. Export the TemplateSelection component from @woocommerce/email-editor so consumers can unregister and re-render it in custom locations. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
PreviousNext