-
Notifications
You must be signed in to change notification settings - Fork 10.7k
Fix Tracks events rejected due to bracket notation in array properties #61729
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: trunk
Are you sure you want to change the base?
Conversation
When arrays are passed to WC_Tracks::record_event(), http_build_query() creates bracket notation in property names (e.g., prop[0], prop[1]) which violates the required naming pattern and causes event rejection. This fix implements automatic array sanitization in validate_and_sanitize(): - Empty arrays → empty string - Indexed arrays with scalars → comma-separated string (URL-encoded) - Associative/nested arrays → JSON string Aligns with Jetpack consumer-side fix: Automattic/jetpack#45544 Changes: - Add sanitize_property_values() method (PHP 7.4+ compatible) - Integrate into validate_and_sanitize() preserving object return type - Document array handling in WC_Tracks::record_event() PHPDoc - Add 8 comprehensive unit tests for all array scenarios 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
|
Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. 📝 WalkthroughWalkthroughAdds a private sanitizer to WC_Tracks_Event that normalizes array-valued event properties (empty arrays → "", indexed scalar arrays → comma-delimited strings, associative/nested arrays → JSON strings), applies it in validate_and_sanitize (docblock updated), adds unit tests, and adds a changelog entry. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant Caller as Event Caller
participant WCEvent as WC_Tracks_Event
participant Validator as validate_and_sanitize()
participant Sanitizer as sanitize_property_values()
participant Pixel as build_pixel_url()
Note over Sanitizer: (new) normalizes array properties:
Note over Sanitizer: - empty arrays -> ""\n- indexed scalar arrays -> comma string\n- associative/nested -> JSON string
Caller->>WCEvent: new WC_Tracks_Event(props)
WCEvent->>Validator: validate_and_sanitize()
Validator->>Sanitizer: sanitize_property_values(props)
Sanitizer-->>Validator: normalized props (strings / JSON)
Validator-->>WCEvent: validated & sanitized event (object or WP_Error)
WCEvent->>Pixel: build_pixel_url()
Pixel-->>Caller: pixel URL (array props serialized, no bracketed params)
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ 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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
📜 Review details
Configuration used: Path: .coderabbit.yml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
plugins/woocommerce/includes/tracks/class-wc-tracks-event.php(3 hunks)plugins/woocommerce/includes/tracks/class-wc-tracks.php(1 hunks)plugins/woocommerce/tests/php/includes/class-wc-tracks-test.php(1 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{php,js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/code-quality.mdc)
**/*.{php,js,jsx,ts,tsx}: Guard against unexpected inputs
Sanitize and validate any potentially dangerous inputs
Ensure code is backwards compatible
Write code that is readable and intuitive
Ensure code has unit or E2E tests where applicable
Files:
plugins/woocommerce/includes/tracks/class-wc-tracks.phpplugins/woocommerce/includes/tracks/class-wc-tracks-event.phpplugins/woocommerce/tests/php/includes/class-wc-tracks-test.php
**/*.{php,js,jsx,tsx,ts}
📄 CodeRabbit inference engine (.cursor/rules/avoid-regex.mdc)
**/*.{php,js,jsx,tsx,ts}: Avoid using regular expressions unless absolutely necessary to favor readability and maintainability
Only consider regex when no built-in language alternative (string/array APIs) fits the need
Only use regex when performance is critical and faster than alternatives, with measurements to justify
Use regex for complex pattern matching only if the pattern is well-documented and thoroughly tested
Allow regex when maintaining legacy code where an existing, correct pattern is being modified
If regex is necessary, document the pattern extensively to explain what it matches
If regex is necessary, add comprehensive tests covering edge cases and potential security issues
Use named capture groups in regex to improve readability when supported
Validate input before applying regex to ensure it is safe
Assess and mitigate security risks when using regex, including ReDoS and injection vulnerabilities
Avoid regex patterns that can cause catastrophic backtracking (ReDoS)
Do not construct regex from untrusted input to prevent injection attacks
Ensure regex patterns do not overmatch and unintentionally capture unexpected inputs
Files:
plugins/woocommerce/includes/tracks/class-wc-tracks.phpplugins/woocommerce/includes/tracks/class-wc-tracks-event.phpplugins/woocommerce/tests/php/includes/class-wc-tracks-test.php
**/*.{php,js,ts,jsx,tsx}
⚙️ CodeRabbit configuration file
**/*.{php,js,ts,jsx,tsx}: Don't trust that extension developers will follow the best practices, make sure the code:
- Guards against unexpected inputs.
- Sanitizes and validates any potentially dangerous inputs.
- Is backwards compatible.
- Is readable and intuitive.
- Has unit or E2E tests where applicable.
When making any changes to code that deletes or modifies orders/products/customer data, make sure that there are
sufficient checks in place to prevent accidental data loss. As an example, if deleting a draft order, check that
the order status is indeeddraftorcheckout-draft. Also think about whether race conditions could occur and
delete orders that don't belong to the current customer. When in doubt, ask for clarification in the PR comments.
Files:
plugins/woocommerce/includes/tracks/class-wc-tracks.phpplugins/woocommerce/includes/tracks/class-wc-tracks-event.phpplugins/woocommerce/tests/php/includes/class-wc-tracks-test.php
plugins/woocommerce/tests/**/*.php
📄 CodeRabbit inference engine (.cursor/rules/woo-phpunit.mdc)
plugins/woocommerce/tests/**/*.php: Ensure test classes define public setUp() and tearDown() methods (not protected)
All PHPUnit test methods must be public, not protected
Add declare(strict_types=1); at the top of each test file
Test classes should extend WC_Unit_Test_Case
Files:
plugins/woocommerce/tests/php/includes/class-wc-tracks-test.php
🧠 Learnings (7)
📓 Common learnings
Learnt from: joshuatf
Repo: woocommerce/woocommerce PR: 60324
File: packages/js/product-editor/src/components/content-preview/content-preview.tsx:83-88
Timestamp: 2025-08-29T09:31:00.392Z
Learning: In WooCommerce sanitization patterns, always defensively coerce inputs to strings before passing to sanitizeHTML using `String( input ?? '' )` to guard against null, undefined, or non-string values that could cause runtime errors.
Learnt from: joshuatf
Repo: woocommerce/woocommerce PR: 60324
File: packages/js/product-editor/src/blocks/generic/toggle/edit.tsx:74-75
Timestamp: 2025-08-29T09:30:44.987Z
Learning: In the WooCommerce woocommerce/sanitize package migration, the design goal is to centralize sanitization with secure defaults. Usage sites should call sanitizeHTML() without explicit allowlist configuration, as the package already provides DEFAULT_ALLOWED_TAGS and DEFAULT_ALLOWED_ATTR with appropriate security boundaries. Adding explicit configuration at every call site defeats the purpose of the centralized approach.
Learnt from: senadir
Repo: woocommerce/woocommerce PR: 59426
File: plugins/woocommerce/client/legacy/js/frontend/a8c-address-autocomplete-service.js:355-355
Timestamp: 2025-07-08T09:14:47.894Z
Learning: In the WooCommerce address autocomplete system, input sanitization happens upstream in address-autocomplete.js before data reaches a8c-address-autocomplete-service.js. The trim() operation in the service file is for optimization purposes (to skip API requests when only spaces are added), not for security sanitization.
📚 Learning: 2025-08-29T09:30:44.987Z
Learnt from: joshuatf
Repo: woocommerce/woocommerce PR: 60324
File: packages/js/product-editor/src/blocks/generic/toggle/edit.tsx:74-75
Timestamp: 2025-08-29T09:30:44.987Z
Learning: In the WooCommerce woocommerce/sanitize package migration, the design goal is to centralize sanitization with secure defaults. Usage sites should call sanitizeHTML() without explicit allowlist configuration, as the package already provides DEFAULT_ALLOWED_TAGS and DEFAULT_ALLOWED_ATTR with appropriate security boundaries. Adding explicit configuration at every call site defeats the purpose of the centralized approach.
Applied to files:
plugins/woocommerce/includes/tracks/class-wc-tracks-event.php
📚 Learning: 2025-08-29T09:31:00.392Z
Learnt from: joshuatf
Repo: woocommerce/woocommerce PR: 60324
File: packages/js/product-editor/src/components/content-preview/content-preview.tsx:83-88
Timestamp: 2025-08-29T09:31:00.392Z
Learning: In WooCommerce sanitization patterns, always defensively coerce inputs to strings before passing to sanitizeHTML using `String( input ?? '' )` to guard against null, undefined, or non-string values that could cause runtime errors.
Applied to files:
plugins/woocommerce/includes/tracks/class-wc-tracks-event.php
📚 Learning: 2025-08-18T06:11:48.768Z
Learnt from: CR
Repo: woocommerce/woocommerce PR: 0
File: .cursor/rules/woo-phpunit.mdc:0-0
Timestamp: 2025-08-18T06:11:48.768Z
Learning: Applies to plugins/woocommerce/tests/**/*.php : Add declare(strict_types=1); at the top of each test file
Applied to files:
plugins/woocommerce/tests/php/includes/class-wc-tracks-test.php
📚 Learning: 2025-08-18T06:11:48.768Z
Learnt from: CR
Repo: woocommerce/woocommerce PR: 0
File: .cursor/rules/woo-phpunit.mdc:0-0
Timestamp: 2025-08-18T06:11:48.768Z
Learning: Applies to plugins/woocommerce/tests/**/*.php : Test classes should extend WC_Unit_Test_Case
Applied to files:
plugins/woocommerce/tests/php/includes/class-wc-tracks-test.php
📚 Learning: 2025-08-18T06:11:48.768Z
Learnt from: CR
Repo: woocommerce/woocommerce PR: 0
File: .cursor/rules/woo-phpunit.mdc:0-0
Timestamp: 2025-08-18T06:11:48.768Z
Learning: Applies to plugins/woocommerce/tests/**/*.php : All PHPUnit test methods must be public, not protected
Applied to files:
plugins/woocommerce/tests/php/includes/class-wc-tracks-test.php
📚 Learning: 2025-09-03T11:50:02.208Z
Learnt from: tpaksu
Repo: woocommerce/woocommerce PR: 60735
File: plugins/woocommerce/tests/php/includes/rest-api/Controllers/Version4/Fulfillments/class-wc-rest-fulfillments-v4-controller-tests.php:10-10
Timestamp: 2025-09-03T11:50:02.208Z
Learning: For REST API controller tests in plugins/woocommerce/tests/**/*.php, test classes should extend WC_REST_Unit_Test_Case instead of WC_Unit_Test_Case because REST routes need to be registered before tests run.
Applied to files:
plugins/woocommerce/tests/php/includes/class-wc-tracks-test.php
🧬 Code graph analysis (1)
plugins/woocommerce/tests/php/includes/class-wc-tracks-test.php (1)
plugins/woocommerce/includes/tracks/class-wc-tracks-event.php (1)
build_pixel_url(118-135)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (32)
- GitHub Check: Blocks e2e tests 6/10 - @woocommerce/plugin-woocommerce [e2e]
- GitHub Check: Blocks e2e tests 3/10 - @woocommerce/plugin-woocommerce [e2e]
- GitHub Check: Blocks e2e tests 8/10 - @woocommerce/plugin-woocommerce [e2e]
- GitHub Check: Blocks e2e tests - Legacy MiniCart 1/3 - @woocommerce/plugin-woocommerce [e2e]
- GitHub Check: Blocks e2e tests 1/10 - @woocommerce/plugin-woocommerce [e2e]
- GitHub Check: Blocks e2e tests 9/10 - @woocommerce/plugin-woocommerce [e2e]
- GitHub Check: Core e2e tests 6/6 - @woocommerce/plugin-woocommerce [e2e]
- GitHub Check: Blocks e2e tests 4/10 - @woocommerce/plugin-woocommerce [e2e]
- GitHub Check: Blocks e2e tests 7/10 - @woocommerce/plugin-woocommerce [e2e]
- GitHub Check: Metrics - @woocommerce/plugin-woocommerce [performance]
- GitHub Check: Blocks e2e tests 10/10 - @woocommerce/plugin-woocommerce [e2e]
- GitHub Check: Blocks e2e tests 5/10 - @woocommerce/plugin-woocommerce [e2e]
- GitHub Check: Blocks e2e tests 2/10 - @woocommerce/plugin-woocommerce [e2e]
- GitHub Check: Core e2e tests - Legacy MiniCart - @woocommerce/plugin-woocommerce [e2e]
- GitHub Check: PHP: 8.4 WP: latest (HPOS:off) [WP latest] 2/2 - @woocommerce/plugin-woocommerce [unit:php]
- GitHub Check: Core e2e tests 5/6 - @woocommerce/plugin-woocommerce [e2e]
- GitHub Check: Core API tests - @woocommerce/plugin-woocommerce [api]
- GitHub Check: PHP: 8.4 WP: latest (HPOS:off) [WP latest] 1/2 - @woocommerce/plugin-woocommerce [unit:php]
- GitHub Check: Core e2e tests 4/6 - @woocommerce/plugin-woocommerce [e2e]
- GitHub Check: Core e2e tests 3/6 - @woocommerce/plugin-woocommerce [e2e]
- GitHub Check: PHP: 8.4 WP: latest - Legacy MiniCart [WP latest] 1/2 - @woocommerce/plugin-woocommerce [unit:php]
- GitHub Check: Core e2e tests 1/6 - @woocommerce/plugin-woocommerce [e2e]
- GitHub Check: PHP: 7.4 WP: pre-release [WP 6.9-beta2] 1/2 - @woocommerce/plugin-woocommerce [unit:php] (optional)
- GitHub Check: PHP: 7.4 WP: pre-release [WP 6.9-beta2] 2/2 - @woocommerce/plugin-woocommerce [unit:php] (optional)
- GitHub Check: PHP: 7.4 WP: latest - 1 [WP 6.7.4] 2/2 - @woocommerce/plugin-woocommerce [unit:php]
- GitHub Check: PHP: 8.4 WP: latest - Legacy MiniCart [WP latest] 2/2 - @woocommerce/plugin-woocommerce [unit:php]
- GitHub Check: Core e2e tests 2/6 - @woocommerce/plugin-woocommerce [e2e]
- GitHub Check: PHP: 8.4 WP: latest [WP latest] 2/2 - @woocommerce/plugin-woocommerce [unit:php]
- GitHub Check: PHP: 8.4 WP: latest [WP latest] 1/2 - @woocommerce/plugin-woocommerce [unit:php]
- GitHub Check: PHP: 7.4 WP: latest - 1 [WP 6.7.4] 1/2 - @woocommerce/plugin-woocommerce [unit:php]
- GitHub Check: Lint - @woocommerce/plugin-woocommerce
- GitHub Check: build
plugins/woocommerce/tests/php/includes/class-wc-tracks-test.php
Outdated
Show resolved
Hide resolved
Test using WordPress PlaygroundThe changes in this pull request can be previewed and tested using a WordPress Playground instance. Test this pull request with WordPress Playground. Note that this URL is valid for 30 days from when this comment was last updated. You can update it by closing/reopening the PR or pushing a new commit. |
Updated the handling of indexed arrays in WC_Tracks_Event to directly use implode for creating comma-separated strings, removing unnecessary URL encoding. Adjusted unit tests to verify the expected string outputs without checking for bracket notation or JSON encoding, ensuring cleaner assertions for URL parameters. Changes: - Simplified value assignment for indexed arrays - Updated assertions in unit tests to check for string containment instead of exact matches This change aligns with the recent improvements in array handling for event tracking.
| * | ||
| * @param array $event Event arguments. | ||
| * @return bool|WP_Error True on success, WP_Error on failure. | ||
| * @return object|WP_Error Event object on success, WP_Error on failure. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed the type hint for the $event parameter to reflect that it returns either an object or a WP_Error, not a boolean.
Testing GuidelinesHi @woocommerce/ventures, Apart from reviewing the code changes, please make sure to review the testing instructions (Guide) and verify that relevant tests (E2E, Unit, Integration, etc.) have been added or updated as needed. Reminder: PR reviewers are required to document testing performed. This includes:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR fixes an issue where WooCommerce Tracks events were being rejected when array properties were passed. The solution automatically converts array properties to valid formats: indexed arrays become comma-separated strings, associative arrays become JSON strings, and empty arrays become empty strings. This prevents http_build_query() from generating bracket notation (e.g., prop[0]) that violates the property name regex.
- Adds automatic array property conversion in
sanitize_property_values()method - Updates documentation to explain the array handling behavior with examples
- Adds comprehensive test coverage for various array scenarios (indexed, associative, nested, empty, with commas, and multiple array properties)
Reviewed Changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
plugins/woocommerce/includes/tracks/class-wc-tracks-event.php |
Adds sanitize_property_values() method to convert arrays before serialization and updates return type documentation |
plugins/woocommerce/includes/tracks/class-wc-tracks.php |
Adds comprehensive documentation explaining array conversion behavior with examples |
plugins/woocommerce/tests/php/includes/class-wc-tracks-test.php |
Adds 7 new test cases covering various array property scenarios |
plugins/woocommerce/changelog/61729-fix-tracks-array-serialization |
Adds changelog entry for the fix |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
|
|
||
| if ( $is_indexed_array && $has_scalar_only ) { | ||
| // Indexed arrays with scalar values: join as comma string. | ||
| $props[ $key ] = implode( ',', array_map( 'strval', $value ) ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This maintains the same behavior as when tracking events in JavaScript.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (1)
plugins/woocommerce/includes/tracks/class-wc-tracks-event.php (1)
147-149: Consider adding defensive input validation.While this private method is currently only called with validated objects, adding a type check would guard against future refactoring risks and align with defensive coding practices.
Apply this diff to add input validation:
private static function sanitize_property_values( $properties ) { + if ( ! is_object( $properties ) && ! is_array( $properties ) ) { + return $properties; + } $is_object = is_object( $properties ); $props = $is_object ? get_object_vars( $properties ) : $properties;As per coding guidelines
📜 Review details
Configuration used: Path: .coderabbit.yml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
plugins/woocommerce/includes/tracks/class-wc-tracks-event.php(3 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{php,js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/code-quality.mdc)
**/*.{php,js,jsx,ts,tsx}: Guard against unexpected inputs
Sanitize and validate any potentially dangerous inputs
Ensure code is backwards compatible
Write code that is readable and intuitive
Ensure code has unit or E2E tests where applicable
Files:
plugins/woocommerce/includes/tracks/class-wc-tracks-event.php
**/*.{php,js,jsx,tsx,ts}
📄 CodeRabbit inference engine (.cursor/rules/avoid-regex.mdc)
**/*.{php,js,jsx,tsx,ts}: Avoid using regular expressions unless absolutely necessary to favor readability and maintainability
Only consider regex when no built-in language alternative (string/array APIs) fits the need
Only use regex when performance is critical and faster than alternatives, with measurements to justify
Use regex for complex pattern matching only if the pattern is well-documented and thoroughly tested
Allow regex when maintaining legacy code where an existing, correct pattern is being modified
If regex is necessary, document the pattern extensively to explain what it matches
If regex is necessary, add comprehensive tests covering edge cases and potential security issues
Use named capture groups in regex to improve readability when supported
Validate input before applying regex to ensure it is safe
Assess and mitigate security risks when using regex, including ReDoS and injection vulnerabilities
Avoid regex patterns that can cause catastrophic backtracking (ReDoS)
Do not construct regex from untrusted input to prevent injection attacks
Ensure regex patterns do not overmatch and unintentionally capture unexpected inputs
Files:
plugins/woocommerce/includes/tracks/class-wc-tracks-event.php
**/*.{php,js,ts,jsx,tsx}
⚙️ CodeRabbit configuration file
**/*.{php,js,ts,jsx,tsx}: Don't trust that extension developers will follow the best practices, make sure the code:
- Guards against unexpected inputs.
- Sanitizes and validates any potentially dangerous inputs.
- Is backwards compatible.
- Is readable and intuitive.
- Has unit or E2E tests where applicable.
When making any changes to code that deletes or modifies orders/products/customer data, make sure that there are
sufficient checks in place to prevent accidental data loss. As an example, if deleting a draft order, check that
the order status is indeeddraftorcheckout-draft. Also think about whether race conditions could occur and
delete orders that don't belong to the current customer. When in doubt, ask for clarification in the PR comments.
Files:
plugins/woocommerce/includes/tracks/class-wc-tracks-event.php
🧠 Learnings (6)
📓 Common learnings
Learnt from: joshuatf
Repo: woocommerce/woocommerce PR: 60324
File: packages/js/product-editor/src/blocks/generic/toggle/edit.tsx:74-75
Timestamp: 2025-08-29T09:30:44.987Z
Learning: In the WooCommerce woocommerce/sanitize package migration, the design goal is to centralize sanitization with secure defaults. Usage sites should call sanitizeHTML() without explicit allowlist configuration, as the package already provides DEFAULT_ALLOWED_TAGS and DEFAULT_ALLOWED_ATTR with appropriate security boundaries. Adding explicit configuration at every call site defeats the purpose of the centralized approach.
📚 Learning: 2025-06-17T07:07:53.443Z
Learnt from: samueljseay
Repo: woocommerce/woocommerce PR: 58716
File: plugins/woocommerce/client/blocks/assets/js/blocks/mini-cart/iapi-frontend.ts:83-101
Timestamp: 2025-06-17T07:07:53.443Z
Learning: In WooCommerce blocks, when porting existing code patterns that have known issues (like parseInt truncating decimal money values), maintain consistency with existing implementation rather than making isolated fixes. The preference is for systematic refactoring approaches (like broader Dinero adoption) over piecemeal changes.
Applied to files:
plugins/woocommerce/includes/tracks/class-wc-tracks-event.php
📚 Learning: 2025-08-29T09:31:00.392Z
Learnt from: joshuatf
Repo: woocommerce/woocommerce PR: 60324
File: packages/js/product-editor/src/components/content-preview/content-preview.tsx:83-88
Timestamp: 2025-08-29T09:31:00.392Z
Learning: In WooCommerce sanitization patterns, always defensively coerce inputs to strings before passing to sanitizeHTML using `String( input ?? '' )` to guard against null, undefined, or non-string values that could cause runtime errors.
Applied to files:
plugins/woocommerce/includes/tracks/class-wc-tracks-event.php
📚 Learning: 2025-08-29T09:30:44.987Z
Learnt from: joshuatf
Repo: woocommerce/woocommerce PR: 60324
File: packages/js/product-editor/src/blocks/generic/toggle/edit.tsx:74-75
Timestamp: 2025-08-29T09:30:44.987Z
Learning: In the WooCommerce woocommerce/sanitize package migration, the design goal is to centralize sanitization with secure defaults. Usage sites should call sanitizeHTML() without explicit allowlist configuration, as the package already provides DEFAULT_ALLOWED_TAGS and DEFAULT_ALLOWED_ATTR with appropriate security boundaries. Adding explicit configuration at every call site defeats the purpose of the centralized approach.
Applied to files:
plugins/woocommerce/includes/tracks/class-wc-tracks-event.php
📚 Learning: 2025-07-08T09:14:47.894Z
Learnt from: senadir
Repo: woocommerce/woocommerce PR: 59426
File: plugins/woocommerce/client/legacy/js/frontend/a8c-address-autocomplete-service.js:355-355
Timestamp: 2025-07-08T09:14:47.894Z
Learning: In the WooCommerce address autocomplete system, input sanitization happens upstream in address-autocomplete.js before data reaches a8c-address-autocomplete-service.js. The trim() operation in the service file is for optimization purposes (to skip API requests when only spaces are added), not for security sanitization.
Applied to files:
plugins/woocommerce/includes/tracks/class-wc-tracks-event.php
📚 Learning: 2025-07-18T14:54:36.232Z
Learnt from: CR
Repo: woocommerce/woocommerce PR: 0
File: .cursor/rules/code-quality.mdc:0-0
Timestamp: 2025-07-18T14:54:36.232Z
Learning: Applies to **/*.{php,js,jsx,ts,tsx} : Sanitize and validate any potentially dangerous inputs
Applied to files:
plugins/woocommerce/includes/tracks/class-wc-tracks-event.php
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (28)
- GitHub Check: Blocks e2e tests 3/10 - @woocommerce/plugin-woocommerce [e2e]
- GitHub Check: Blocks e2e tests - Legacy MiniCart 1/3 - @woocommerce/plugin-woocommerce [e2e]
- GitHub Check: Blocks e2e tests 9/10 - @woocommerce/plugin-woocommerce [e2e]
- GitHub Check: Blocks e2e tests 7/10 - @woocommerce/plugin-woocommerce [e2e]
- GitHub Check: Blocks e2e tests 6/10 - @woocommerce/plugin-woocommerce [e2e]
- GitHub Check: Blocks e2e tests 8/10 - @woocommerce/plugin-woocommerce [e2e]
- GitHub Check: Blocks e2e tests 10/10 - @woocommerce/plugin-woocommerce [e2e]
- GitHub Check: Blocks e2e tests 4/10 - @woocommerce/plugin-woocommerce [e2e]
- GitHub Check: PHP: 8.4 WP: latest (HPOS:off) [WP latest] 2/2 - @woocommerce/plugin-woocommerce [unit:php]
- GitHub Check: PHP: 8.4 WP: latest (HPOS:off) [WP latest] 1/2 - @woocommerce/plugin-woocommerce [unit:php]
- GitHub Check: Core e2e tests 6/6 - @woocommerce/plugin-woocommerce [e2e]
- GitHub Check: Metrics - @woocommerce/plugin-woocommerce [performance]
- GitHub Check: Core e2e tests 2/6 - @woocommerce/plugin-woocommerce [e2e]
- GitHub Check: Blocks e2e tests 2/10 - @woocommerce/plugin-woocommerce [e2e]
- GitHub Check: Core API tests - @woocommerce/plugin-woocommerce [api]
- GitHub Check: Core e2e tests - Legacy MiniCart - @woocommerce/plugin-woocommerce [e2e]
- GitHub Check: Core e2e tests 4/6 - @woocommerce/plugin-woocommerce [e2e]
- GitHub Check: Core e2e tests 5/6 - @woocommerce/plugin-woocommerce [e2e]
- GitHub Check: PHP: 7.4 WP: latest - 1 [WP 6.7.4] 1/2 - @woocommerce/plugin-woocommerce [unit:php]
- GitHub Check: PHP: 7.4 WP: pre-release [WP 6.9-beta2] 2/2 - @woocommerce/plugin-woocommerce [unit:php] (optional)
- GitHub Check: PHP: 7.4 WP: pre-release [WP 6.9-beta2] 1/2 - @woocommerce/plugin-woocommerce [unit:php] (optional)
- GitHub Check: Core e2e tests 1/6 - @woocommerce/plugin-woocommerce [e2e]
- GitHub Check: PHP: 7.4 WP: latest - 1 [WP 6.7.4] 2/2 - @woocommerce/plugin-woocommerce [unit:php]
- GitHub Check: PHP: 8.4 WP: latest [WP latest] 2/2 - @woocommerce/plugin-woocommerce [unit:php]
- GitHub Check: PHP: 8.4 WP: latest - Legacy MiniCart [WP latest] 1/2 - @woocommerce/plugin-woocommerce [unit:php]
- GitHub Check: PHP: 8.4 WP: latest [WP latest] 1/2 - @woocommerce/plugin-woocommerce [unit:php]
- GitHub Check: Lint - @woocommerce/plugin-woocommerce
- GitHub Check: build
🔇 Additional comments (4)
plugins/woocommerce/includes/tracks/class-wc-tracks-event.php (4)
69-69: LGTM!The updated return type documentation accurately reflects that the method returns an event object on success or
WP_Erroron failure.
106-108: LGTM!The sanitization is correctly placed after all validation checks, ensuring only valid events are processed. The method preserves the object type, maintaining consistency with the return type.
177-179: Excellent error handling for JSON encoding.The use of
JSON_HEX_TAGprovides XSS protection by escaping HTML-sensitive characters, and the fallback to an empty string on encoding failure prevents events from being rejected entirely due to malformed UTF-8 or other encoding issues.
182-182: LGTM!The method correctly preserves the input type (object or array), ensuring consistent behavior and maintaining the API contract described in the docblock.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (1)
plugins/woocommerce/includes/tracks/class-wc-tracks-event.php (1)
147-147: Consider adding type hints for better type safety.Adding explicit type hints would make the method contract clearer and enable static analysis tools to catch potential type mismatches.
Consider this optional enhancement:
- private static function sanitize_property_values( $properties ) { + private static function sanitize_property_values( object|array $properties ): object|array {Note: This requires PHP 8.0+. If supporting earlier PHP versions, this can be deferred.
📜 Review details
Configuration used: Path: .coderabbit.yml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
plugins/woocommerce/includes/tracks/class-wc-tracks-event.php(3 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{php,js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/code-quality.mdc)
**/*.{php,js,jsx,ts,tsx}: Guard against unexpected inputs
Sanitize and validate any potentially dangerous inputs
Ensure code is backwards compatible
Write code that is readable and intuitive
Ensure code has unit or E2E tests where applicable
Files:
plugins/woocommerce/includes/tracks/class-wc-tracks-event.php
**/*.{php,js,jsx,tsx,ts}
📄 CodeRabbit inference engine (.cursor/rules/avoid-regex.mdc)
**/*.{php,js,jsx,tsx,ts}: Avoid using regular expressions unless absolutely necessary to favor readability and maintainability
Only consider regex when no built-in language alternative (string/array APIs) fits the need
Only use regex when performance is critical and faster than alternatives, with measurements to justify
Use regex for complex pattern matching only if the pattern is well-documented and thoroughly tested
Allow regex when maintaining legacy code where an existing, correct pattern is being modified
If regex is necessary, document the pattern extensively to explain what it matches
If regex is necessary, add comprehensive tests covering edge cases and potential security issues
Use named capture groups in regex to improve readability when supported
Validate input before applying regex to ensure it is safe
Assess and mitigate security risks when using regex, including ReDoS and injection vulnerabilities
Avoid regex patterns that can cause catastrophic backtracking (ReDoS)
Do not construct regex from untrusted input to prevent injection attacks
Ensure regex patterns do not overmatch and unintentionally capture unexpected inputs
Files:
plugins/woocommerce/includes/tracks/class-wc-tracks-event.php
**/*.{php,js,ts,jsx,tsx}
⚙️ CodeRabbit configuration file
**/*.{php,js,ts,jsx,tsx}: Don't trust that extension developers will follow the best practices, make sure the code:
- Guards against unexpected inputs.
- Sanitizes and validates any potentially dangerous inputs.
- Is backwards compatible.
- Is readable and intuitive.
- Has unit or E2E tests where applicable.
When making any changes to code that deletes or modifies orders/products/customer data, make sure that there are
sufficient checks in place to prevent accidental data loss. As an example, if deleting a draft order, check that
the order status is indeeddraftorcheckout-draft. Also think about whether race conditions could occur and
delete orders that don't belong to the current customer. When in doubt, ask for clarification in the PR comments.
Files:
plugins/woocommerce/includes/tracks/class-wc-tracks-event.php
🧠 Learnings (6)
📓 Common learnings
Learnt from: joshuatf
Repo: woocommerce/woocommerce PR: 60324
File: packages/js/product-editor/src/blocks/generic/toggle/edit.tsx:74-75
Timestamp: 2025-08-29T09:30:44.987Z
Learning: In the WooCommerce woocommerce/sanitize package migration, the design goal is to centralize sanitization with secure defaults. Usage sites should call sanitizeHTML() without explicit allowlist configuration, as the package already provides DEFAULT_ALLOWED_TAGS and DEFAULT_ALLOWED_ATTR with appropriate security boundaries. Adding explicit configuration at every call site defeats the purpose of the centralized approach.
📚 Learning: 2025-08-29T09:30:44.987Z
Learnt from: joshuatf
Repo: woocommerce/woocommerce PR: 60324
File: packages/js/product-editor/src/blocks/generic/toggle/edit.tsx:74-75
Timestamp: 2025-08-29T09:30:44.987Z
Learning: In the WooCommerce woocommerce/sanitize package migration, the design goal is to centralize sanitization with secure defaults. Usage sites should call sanitizeHTML() without explicit allowlist configuration, as the package already provides DEFAULT_ALLOWED_TAGS and DEFAULT_ALLOWED_ATTR with appropriate security boundaries. Adding explicit configuration at every call site defeats the purpose of the centralized approach.
Applied to files:
plugins/woocommerce/includes/tracks/class-wc-tracks-event.php
📚 Learning: 2025-06-17T07:07:53.443Z
Learnt from: samueljseay
Repo: woocommerce/woocommerce PR: 58716
File: plugins/woocommerce/client/blocks/assets/js/blocks/mini-cart/iapi-frontend.ts:83-101
Timestamp: 2025-06-17T07:07:53.443Z
Learning: In WooCommerce blocks, when porting existing code patterns that have known issues (like parseInt truncating decimal money values), maintain consistency with existing implementation rather than making isolated fixes. The preference is for systematic refactoring approaches (like broader Dinero adoption) over piecemeal changes.
Applied to files:
plugins/woocommerce/includes/tracks/class-wc-tracks-event.php
📚 Learning: 2025-08-29T09:31:00.392Z
Learnt from: joshuatf
Repo: woocommerce/woocommerce PR: 60324
File: packages/js/product-editor/src/components/content-preview/content-preview.tsx:83-88
Timestamp: 2025-08-29T09:31:00.392Z
Learning: In WooCommerce sanitization patterns, always defensively coerce inputs to strings before passing to sanitizeHTML using `String( input ?? '' )` to guard against null, undefined, or non-string values that could cause runtime errors.
Applied to files:
plugins/woocommerce/includes/tracks/class-wc-tracks-event.php
📚 Learning: 2025-07-08T09:14:47.894Z
Learnt from: senadir
Repo: woocommerce/woocommerce PR: 59426
File: plugins/woocommerce/client/legacy/js/frontend/a8c-address-autocomplete-service.js:355-355
Timestamp: 2025-07-08T09:14:47.894Z
Learning: In the WooCommerce address autocomplete system, input sanitization happens upstream in address-autocomplete.js before data reaches a8c-address-autocomplete-service.js. The trim() operation in the service file is for optimization purposes (to skip API requests when only spaces are added), not for security sanitization.
Applied to files:
plugins/woocommerce/includes/tracks/class-wc-tracks-event.php
📚 Learning: 2025-07-18T14:54:36.232Z
Learnt from: CR
Repo: woocommerce/woocommerce PR: 0
File: .cursor/rules/code-quality.mdc:0-0
Timestamp: 2025-07-18T14:54:36.232Z
Learning: Applies to **/*.{php,js,jsx,ts,tsx} : Sanitize and validate any potentially dangerous inputs
Applied to files:
plugins/woocommerce/includes/tracks/class-wc-tracks-event.php
🔇 Additional comments (3)
plugins/woocommerce/includes/tracks/class-wc-tracks-event.php (3)
69-69: LGTM: Accurate return type documentation.The updated docblock correctly reflects that the method returns either an object or a
WP_Error, not a boolean.
106-107: LGTM: Proper sanitization placement.Calling
sanitize_property_values()after property name validation ensures that array values are normalized before serialization, preventing bracket notation in the generated URLs.
147-183: LGTM: Robust array sanitization with proper error handling.The implementation correctly handles all specified array conversion cases:
- Empty arrays → empty string
- Indexed scalar arrays → comma-separated string (without double-encoding)
- Associative/nested arrays → JSON string with safe encoding flags
The logic is defensive, preserves input type (object vs array), and properly checks for JSON encoding failures.
Submission Review Guidelines:
Changes proposed in this Pull Request:
Closes WOOPLUG-5767
Fixes a bug in WooCommerce Tracks where array event properties are incorrectly serialized, causing events to be rejected due to invalid property names.
Problem:
When arrays are passed as event properties to
WC_Tracks::record_event(), thehttp_build_query()function converts them into bracket notation.For example:
additional_blocks_on_checkout_page[0]=value1&additional_blocks_on_checkout_page[1]=value2. These property names with brackets ([0],[1]) violate the required property naming convention (/^[a-z_][a-z0-9_]*$/), causing Tracks events to be rejected.Solution:
This PR implements automatic array value sanitization in
WC_Tracks_Event::validate_and_sanitize():''['a', 'b', 'c']) → URL-encoded comma-separated string'a,b,c'['key' => 'val']) → JSON string'{"key":"val"}'Changes:
sanitize_property_values()method to handle array conversionvalidate_and_sanitize()to ensure consistent return type (object)WC_Tracks::record_event()with examples and documentationHow to test the changes in this Pull Request:
Using the WooCommerce Testing Instructions Guide:
Automated Testing
Run the WC Tracks unit tests:
Verify all 8 new array-related tests pass.
Manual Testing
functions.phpor a custom plugin:wp-content/debug.logblocks=woocommerce%2Fcart-items%2Cwoocommerce%2Fcheckout-totals(comma-separated)settings=%7B%22enabled%22%3Atrue%2C%22count%22%3A5%7D(JSON encoded)items=%5B%7B%22id%22%3A1...(JSON encoded)blocks[0]=valueorblocks%5B0%5D=valueitems[0][id]=1or similarTesting that has already taken place:
Changelog entry
Changelog Entry Details
Significance
Type
Message
Fix Tracks events being rejected when array properties are passed by automatically converting arrays to valid formats