Skip to content

Commit c80be0f

Browse files
David Evbodaghemeta-codesync[bot]
authored andcommitted
Fix click_id API validation error (#3668)
Summary: ## Description After WooC 3.5.10 added ParamBuilder integration for improved fbc/fbp coverage, the plugin started receiving API validation errors from Facebook's Conversions API: **Error:** `Server Side Api Parameter Error: Unexpected key "click_id" on param "$['data'][0]['user_data']"` This fix addresses the root causes: **Problem 1: Broken conditional logic in `get_click_id()`** The original code had `else if ( ! $fbc )` after checking for cookies. Since `$fbc` was initialized as an empty string `''`, this condition always evaluated to true when the cookie was empty, preventing subsequent checks from executing. The priority order was broken. **Problem 2: Empty/null values sent to API** When ParamBuilder or other sources returned null or empty values, these were still being sent to Facebook's API because: - Empty strings pass `isset()` checks (returns true for `''`) - The transformation code only conditionally removed the keys - `array_filter()` only filters the top-level array, not nested `user_data` **Changes Made:** 1. **Updated FBC/FBP priority order** (in `Event.php`): - **FBC Priority:** Cookie → ParamBuilder → Request parameter (`fbclid`) → Session - **FBP Priority:** Cookie → ParamBuilder → Session - Uses `empty()` checks instead of if-elseif-else to allow fallthrough to each source 2. **Simplified transformation checks** (in `Request.php`): - Use `! empty()` directly instead of `isset() && ! empty()` (redundant since `empty()` handles undefined keys) - Only copy to `fbc`/`fbp` when non-empty values exist 3. **Unconditional cleanup:** - Always unset `click_id` and `browser_id` keys after processing to ensure they're never sent to the API 4. **Return null for empty values:** - Changed both `get_click_id()` and `get_browser_id()` to return `null` instead of empty string when no value found This ensures that `click_id` and `browser_id` (internal parameter names) are never sent to Facebook's API, only their transformed equivalents (`fbc` and `fbp`) when valid values exist. ### Type of change - [x] Fix (non-breaking change which fixes an issue) ## Checklist - [x] I have commented my code, particularly in hard-to-understand areas, if any. - [x] I have confirmed that my changes do not introduce any new PHPCS warnings or errors. - [x] I have checked plugin debug logs that my changes do not introduce any new PHP warnings or FATAL errors. - [x] I followed general Pull Request best practices. Meta employees to follow this [wiki]([url](https://fburl.com/wiki/2cgfduwc)). - [ ] I have added tests (if necessary) and all the new and existing unit tests pass locally with my changes. - [x] I have completed dogfooding and QA testing, or I have conducted thorough due diligence to ensure that it does not break existing functionality. - [ ] I have updated or requested update to plugin documentations (if necessary). Meta employees to follow this [wiki]([url](https://fburl.com/wiki/nhx73tgs)). ## Changelog entry Fixed API validation error where click_id parameter was being sent to Facebook Conversions API instead of being properly transformed to fbc. Pull Request resolved: #3668 Test Plan: Manually tested the following scenarios to verify the new FBC/FBP priority order: 1. **Cookie exists** - Uses cookie value (highest priority for both FBC and FBP) 2. **No cookie, ParamBuilder returns value** - Uses ParamBuilder value (2nd priority) 3. **No cookie, no ParamBuilder, fbclid in URL** - Creates fbc from query parameter (3rd priority, FBC only) 4. **Session fallback** - Uses session value when all above unavailable (lowest priority) 5. **Empty/null from all sources** - Returns null, does not send empty click_id/browser_id to API Verified using browser dev tools and API payload inspection that `click_id` and `browser_id` are never present in the final payload sent to Facebook's Conversions API. Only their transformed equivalents (`fbc` and `fbp`) are sent when valid values exist. Ran `arc lint` to confirm no PHPCS violations introduced. ## Screenshots N/A - This is a backend API integration fix with no UI changes. Reviewed By: jarretth Differential Revision: D84942070 Pulled By: devbodaghe fbshipit-source-id: c5171f70e46043b1877753e019d470465f9b5f69
1 parent b950b45 commit c80be0f

4 files changed

Lines changed: 495 additions & 18 deletions

File tree

includes/API/Pixel/Events/Request.php

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -63,20 +63,22 @@ public function get_data() {
6363

6464
$event_data = $event->get_data();
6565

66-
if ( isset( $event_data['user_data']['click_id'] ) ) {
66+
if ( ! empty( $event_data['user_data']['click_id'] ) ) {
6767

6868
$event_data['user_data']['fbc'] = $event_data['user_data']['click_id'];
69-
70-
unset( $event_data['user_data']['click_id'] );
7169
}
7270

73-
if ( isset( $event_data['user_data']['browser_id'] ) ) {
71+
if ( ! empty( $event_data['user_data']['browser_id'] ) ) {
7472

7573
$event_data['user_data']['fbp'] = $event_data['user_data']['browser_id'];
76-
77-
unset( $event_data['user_data']['browser_id'] );
7874
}
7975

76+
// These are valid field names, so when they're provided they
77+
// create event validation issues.
78+
// unset these no matter what.
79+
unset( $event_data['user_data']['click_id'] );
80+
unset( $event_data['user_data']['browser_id'] );
81+
8082
$data['data'][] = array_filter( $event_data );
8183
}
8284

includes/Events/Event.php

Lines changed: 37 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,13 @@ protected function get_client_user_agent() {
250250

251251
/**
252252
* Gets the click ID from the cookie or the query parameter.
253+
* In order, rely on:
254+
* 1. If an _fbc cookie is set
255+
* 2. If we have stored fbc in the session
256+
* 3. The FBC result from param builder
257+
* 4. Construct our own FBC
258+
*
259+
* The resulting value is stored in the session for future requests.
253260
*
254261
* @see https://developers.facebook.com/docs/marketing-api/server-side-api/parameters/fbp-and-fbc#fbp-and-fbc-parameters
255262
*
@@ -261,43 +268,61 @@ protected function get_click_id() {
261268
$fbc = '';
262269
if ( ! empty( $_COOKIE['_fbc'] ) ) {
263270
$fbc = wc_clean( wp_unslash( $_COOKIE['_fbc'] ) );
264-
} else if ( ! $fbc ) {
271+
}
272+
273+
if ( empty( $fbc ) && ! empty( $_SESSION['_fbc'] ) ) {
274+
$fbc = $_SESSION['_fbc']; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
275+
}
276+
277+
if ( empty( $fbc ) ) {
265278
$param_builder = \WC_Facebookcommerce_EventsTracker::get_param_builder();
266279
$fbc = $param_builder->getFbc();
267-
} elseif ( isset( $_REQUEST['fbclid'] ) ) {
280+
}
281+
282+
if ( empty( $fbc ) && ! empty( $_REQUEST['fbclid'] ) ) {
268283
$creation_time = time();
269284
$fbclid = wc_clean( wp_unslash( $_REQUEST['fbclid'] ) ); // phpcs:ignore WordPress.Security.NonceVerification
270285
$fbc = "fb.1.{$creation_time}.{$fbclid}";
271-
} elseif ( isset( $_SESSION['_fbc'] ) ) {
272-
$fbc = $_SESSION['_fbc']; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
273286
}
274-
if ( $fbc ) {
287+
288+
if ( ! empty( $fbc ) ) {
275289
$_SESSION['_fbc'] = $fbc;
276290
}
277-
return $fbc;
291+
// Return null instead of empty string
292+
return ! empty( $fbc ) ? $fbc : null;
278293
}
279294

280295

281296
/**
282297
* Gets the browser ID from the cookie.
298+
* In order, rely on:
299+
* 1. If an _fbp cookie is set
300+
* 2. If we have stored fbp in the session
301+
* 3. The FBP result from param builder
302+
*
303+
* The resulting value is stored in the session for future requests.
283304
*
284305
* @since 2.0.0
285306
*
286307
* @return string
287308
*/
288309
protected function get_browser_id() {
289310
$fbp = ! empty( $_COOKIE['_fbp'] ) ? wc_clean( wp_unslash( $_COOKIE['_fbp'] ) ) : '';
290-
if ( ! $fbp ) {
311+
312+
if ( empty( $fbp ) && ! empty( $_SESSION['_fbp'] ) ) {
313+
$fbp = $_SESSION['_fbp']; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
314+
}
315+
316+
if ( empty( $fbp ) ) {
291317
$param_builder = \WC_Facebookcommerce_EventsTracker::get_param_builder();
292318
$fbp = $param_builder->getFbp();
293319
}
294-
if ( ! $fbp && isset( $_SESSION['_fbp'] ) ) {
295-
$fbp = $_SESSION['_fbp']; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
296-
}
297-
if ( $fbp ) {
320+
321+
if ( ! empty( $fbp ) ) {
298322
$_SESSION['_fbp'] = $fbp;
299323
}
300-
return $fbp;
324+
// Return null instead of empty string
325+
return ! empty( $fbp ) ? $fbp : null;
301326
}
302327

303328

0 commit comments

Comments
 (0)