Upd. Integrations. Improve ajax prefilter. - #889
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## dev #889 +/- ##
=========================================
Coverage 30.56% 30.56%
Complexity 6637 6637
=========================================
Files 292 292
Lines 26489 26489
=========================================
Hits 8097 8097
Misses 18392 18392 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
🟡 Changes recommended
Unresolved artifact coverage and payload-handling issues block approval.
Get a fresh assessment by requesting another Copilot review.
Pull request overview
Improves CleanTalk’s jQuery AJAX interception with ajaxPrefilter and broader payload handling.
Changes:
- Replaces
ajaxSetup.beforeSendinterception. - Adds payload normalization and CleanTalk data injection.
- Updates source, prebuild, and default minified bundle artifacts.
File summaries
| File | Summary |
|---|---|
js/src/public-1-main.js |
Implements the interceptor. Critical (2 votes): protection and gathering minified variants still lack the new dispatcher. Moderate (3 votes): object serialization ignores traditional. Moderate (1 vote): URLSearchParams receives no CleanTalk fields. |
js/prebuild/apbct-public-bundle.js |
Updated generated default bundle. |
js/prebuild/apbct-public-bundle_int-protection.js |
Updated generated internal-protection bundle. |
js/prebuild/apbct-public-bundle_int-protection_gathering.js |
Updated generated internal gathering bundle. |
js/prebuild/apbct-public-bundle_gathering.js |
Updated generated gathering bundle. |
js/prebuild/apbct-public-bundle_full-protection.js |
Updated generated full-protection bundle. |
js/prebuild/apbct-public-bundle_full-protection_gathering.js |
Updated generated full gathering bundle. |
js/prebuild/apbct-public-bundle_ext-protection.js |
Updated generated external-protection bundle. |
js/prebuild/apbct-public-bundle_ext-protection_gathering.js |
Updated generated external gathering bundle. |
js/apbct-public-bundle.min.js |
Updated default minified bundle. |
Review details
Suppressed comments (1)
js/src/public-1-main.js:1341
URLSearchParamshasforEach,get, andappend, so it is recognized bygetJQAjaxDataAsStringand routed into this branch. However,injectCleantalkDataToJQAjaxFormDataonly acceptsinstanceof FormData, returns the URLSearchParams unchanged, and the CleanTalk fields are never added. Handle URLSearchParams separately (for example, inject into itstoString()result) or broaden the helper's accepted payload contract.
if (
typeof ajaxData === 'object' &&
ajaxData !== null &&
typeof ajaxData.append === 'function'
) {
return this.injectCleantalkDataToJQAjaxFormData(sourceSign, ajaxData);
- Files reviewed: 9/17 changed files
- Comments generated: 2
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
There was a problem hiding this comment.
🟡 Changes recommended
Critical payload handling and production-bundle/IE11 compatibility issues remain unresolved.
Get a fresh assessment by requesting another Copilot review.
Review details
Suppressed comments (2)
js/src/public-1-main.js:1177
- The bundles selected by
ApbctJsBundleResolverare the eightjs/apbct-public-bundle*.min.jsartifacts, but none of those served files containsajaxPrefilter; this implementation exists only in the source/prebuild copies. As a result, production requests still execute the old jQuery interception and do not receive this change. Rebuild and commit all minified variants from this source (including the_gatheringvariants).
if ( typeof jQuery !== 'undefined' && typeof jQuery.ajaxPrefilter === 'function' ) {
jQuery.ajaxPrefilter(function(options, originalOptions, jqXHR) {
const handler = new ApbctHandler();
const sourceSign = handler.searchSignsForJQAjaxInjection(options);
if (sourceSign.found !== false) {
js/src/public-1-main.js:1207
FormData.forEachis not available in IE11, while the bundles are explicitly transpiled for IE11 (gulpfile.js:224). In that browser this call throws and the catch returns an empty string, so every FormData request misses its integration sign and receives no CleanTalk data. Use a compatibility-safe way to inspect the action or retain a FormData-specific fallback.
ajaxObject.data.forEach(function(value, key) {
- Files reviewed: 9/17 changed files
- Comments generated: 1
- Review effort level: Lite
There was a problem hiding this comment.
🟡 Changes recommended
Address the three moderate payload-handling and nonce-detection issues in the AJAX prefilter.
Get a fresh assessment by requesting another Copilot review.
Review details
Suppressed comments (1)
js/src/public-1-main.js:1228
- Returning as soon as an
actionfield exists means a FormData request containingaction=user_registrationnever includesur_frontend_form_nonceindataString, so the compound signature at lines 1287-1290 is not detected and no CleanTalk data is injected. Only use theget('action')shortcut when enumeration is unavailable; otherwise serialize all entries (or explicitly include the nonce).
if ( typeof formData.get === 'function' ) {
const action = formData.get('action');
if ( action ) {
return 'action=' + action;
- Files reviewed: 9/17 changed files
- Comments generated: 2
- Review effort level: Lite
There was a problem hiding this comment.
🟡 Changes recommended
Four moderate issues affect FormData handling, array injection, and IE11 compatibility.
Get a fresh assessment by requesting another Copilot review.
Review details
Suppressed comments (3)
js/src/public-1-main.js:1481
- The bundles are transpiled for IE11, but Babel does not polyfill
Object.assign; IE11 reaches this branch for a recognizedprocessData: falseplain-object request and throws before the AJAX call is sent. Use an IE11-compatible shallow-copy implementation or provide a guaranteed polyfill.
const result = Object.prototype.toString.call(ajaxData) === '[object Array]' ?
ajaxData.slice() :
Object.assign({}, ajaxData);
js/src/public-1-main.js:1237
- IE11's FormData implementation has neither
forEachnorget, so this fallback returns an empty string for every FormData payload. The new prefilter therefore never recognizes any supported action or injects fields for FormData requests in the IE11 target; use an IE11-compatible signal (for example, request metadata/URL) or remove the unsupported fallback claim.
if ( typeof formData.get !== 'function' ) {
return '';
js/src/public-1-main.js:1484
- When
ajaxDatais an array, these assignments add named properties such asdata[ct_no_cookie_hidden_field], not array elements. Standard serialization (JSON.stringifyorjQuery.param) ignores those properties, so aprocessData: falsearray request is sent without the injected fields despite this branch claiming to preserve/inject it. Handle the integration's expected array-entry format explicitly or exclude arrays from this path.
const pairs = this.getCleantalkJQAjaxFieldPairs(sourceSign);
for ( let i = 0; i < pairs.length; i++ ) {
result[pairs[i][0]] = pairs[i][1];
- Files reviewed: 9/17 changed files
- Comments generated: 1
- Review effort level: Lite
There was a problem hiding this comment.
🟡 Changes recommended
Four moderate issues remain in AJAX payload handling and should be addressed before approval.
Get a fresh assessment by requesting another Copilot review.
Review details
Suppressed comments (3)
js/src/public-1-main.js:1395
- With
processData: false, this passes the caller-ownedURLSearchParamsinstance directly to a helper that appends CleanTalk fields. Reusing the same params object for a later AJAX call permanently retains the previous token/browser-state values, so requests accumulate duplicate or stale fields. Clone the params before injecting, as the plain-object path already does.
if ( keepOriginalType ) {
return this.injectCleantalkDataToJQAjaxKeyValue(sourceSign, ajaxData);
js/src/public-1-main.js:1391
- The URL-only WooCommerce path is recognized in
searchSignsForJQAjaxInjection, but when such a request has nodata, this dispatcher falls through and returnsundefinedunchanged. The prefilter therefore injects nothing into a validwc-ajax=add_to_cartrequest with an omitted body; treatnull/undefinedas an empty string before calling the string injector, then regenerate the tracked bundles.
if ( typeof ajaxData === 'string' ) {
return this.injectCleantalkDataToJQAjaxString(sourceSign, ajaxData);
js/src/public-1-main.js:1207
- Because this prefilter runs for every jQuery AJAX call, these branches now fully traverse/serialize every plain object, array, and (where supported) FormData just to search for a sign, including unrelated requests; recognized object payloads are then serialized again in
injectCleantalkDataToJQAjax. On pages with frequent or large AJAX payloads this adds avoidable O(payload) work to the global hook. Reuse the serialized representation for injection or add a cheaper candidate check before doing full serialization.
if ( typeof ajaxObject.data === 'string' ) {
return ajaxObject.data;
}
if ( typeof URLSearchParams !== 'undefined' && ajaxObject.data instanceof URLSearchParams ) {
return ajaxObject.data.toString();
}
if ( typeof FormData !== 'undefined' && ajaxObject.data instanceof FormData ) {
return this.getFormDataAsString(ajaxObject.data);
}
if ( this.isJQAjaxPlainObjectOrArray(ajaxObject.data) ) {
- Files reviewed: 9/17 changed files
- Comments generated: 1
- Review effort level: Lite
There was a problem hiding this comment.
🔵 Needs a closer look
Three moderate issues remain in FormData and array payload detection and injection.
Review details
Suppressed comments (3)
js/src/public-1-main.js:1252
- When FormData implements both
get()andforEach()(the normal modern-browser case), this early branch returns after probing onlyaction,ur_frontend_form_nonce, andtwt_cc_signup. Supported submissions such asaction=mailpoetoraction=nf_ajax_submitare therefore not recognized, so their CleanTalk and visible-field data is never injected. Use the enumeration path whenever it is available and keep theget()probes only as a fallback.
if ( typeof formData.get === 'function' ) {
const keysToProbe = [
'action',
'ur_frontend_form_nonce',
'twt_cc_signup',
js/src/public-1-main.js:1238
- Arrays are explicitly supported by
isJQAjaxPlainObjectOrArray, but this candidate check only inspectsdata.actionand an owntwt_cc_signupproperty. A normal$(form).serializeArray()payload is an array of{name: 'action', value: '...'}entries, so it is rejected beforejQuery.param()and no supported integration is detected; the previous prefilter saw the serialized action. Scan array entries for named fields before returning false.
if ( typeof data.action === 'string' && data.action !== '' ) {
return true;
}
return Object.prototype.hasOwnProperty.call(data, 'twt_cc_signup');
js/src/public-1-main.js:1437
- The URL-only WooCommerce sign is also accepted for array payloads, but this branch returns every array unchanged when
processData: false. Awc-ajax=add_to_cartrequest using an array body therefore passes through the new prefilter without any CleanTalk fields, even though arrays are explicitly treated as supported above. Handle this array case explicitly (or reject it before marking the request as injectable) instead of silently skipping the injection.
if ( this.isJQAjaxPlainObjectOrArray(ajaxData) ) {
if ( keepOriginalType ) {
if ( Object.prototype.toString.call(ajaxData) === '[object Array]' ) {
return ajaxData;
- Files reviewed: 9/17 changed files
- Comments generated: 0 new
- Review effort level: Lite
There was a problem hiding this comment.
🔵 Needs a closer look
Five moderate review findings remain in the AJAX prefilter and payload-handling logic.
Review details
Suppressed comments (5)
js/src/public-1-main.js:1213
- For every plain-object request whose payload has any
action, this call runsjQuery.param()once for sign detection, then the dispatcher serializes the same payload again before returning it. Unsupported WordPress AJAX actions therefore pay for two full serializations, and large/nested payloads can incur a noticeable prefilter cost. Detect the supported signs from the structured payload or carry the serialized result into injection so the payload is serialized only once.
try {
if ( typeof jQuery !== 'undefined' && typeof jQuery.param === 'function' ) {
return jQuery.param(ajaxObject.data, ajaxObject.traditional);
js/src/public-1-main.js:1271
- An empty
$(form).serializeArray()is a valid payload. For a URL-onlywc-ajax=add_to_cartrequest withprocessData: false, URL sign detection succeeds, but this predicate rejects[]and the dispatcher returns it unchanged, so no CleanTalk fields are sent. Treat an empty array as a serializeArray payload.
if ( Object.prototype.toString.call(data) !== '[object Array]' || data.length === 0 ) {
js/src/public-1-main.js:1475
- This rejects valid
FormDatainstances created by another window (and common FormData polyfills), becauseinstanceof FormDatais realm-specific. The prefilter then returns the payload unchanged, whereas the previousappendduck check handled it; use a cross-realm-safe check here and in the existing FormData injector.
if ( typeof FormData !== 'undefined' && ajaxData instanceof FormData ) {
return this.injectCleantalkDataToJQAjaxFormData(
sourceSign,
this.cloneFormData(ajaxData),
);
js/src/public-1-main.js:1259
- For serializeArray data, this gate checks
twt_cc_signuponly inentry.name. A serialized form commonly carries the form identifier as a value (for example{name: 'form_id', value: 'twt_cc_signup'}), which the old substring search recognized; this new gate returns false and prevents sign detection and injection. Check the entry value as well as its name.
if ( entry.name === 'twt_cc_signup' ) {
return true;
js/src/public-1-main.js:1241
- This candidate gate no longer searches the serialized object for
twt_cc_signup; it only accepts that marker when it is an own property name. A valid form payload such as{form_id: 'twt_cc_signup'}is therefore rejected beforejQuery.param()andsearchSignsForJQAjaxInjection()runs, so the request receives no CleanTalk fields. The previous string-based path matched this marker anywhere (and the form handling identifies it as an id), so include string-valued properties when deciding whether to serialize the object.
if ( typeof data.action === 'string' && data.action !== '' ) {
return true;
}
return Object.prototype.hasOwnProperty.call(data, 'twt_cc_signup');
- Files reviewed: 9/17 changed files
- Comments generated: 0 new
- Review effort level: Lite
There was a problem hiding this comment.
🔵 Needs a closer look
The moderate URLSearchParams handling issue must be corrected before approval.
Review details
Suppressed comments (8)
js/prebuild/apbct-public-bundle.js:4338
- jQuery skips its data serialization when
contentType: false, even ifprocessDataremains true. A recognizedURLSearchParamsrequest using that option is converted to a plain string below, so XHR no longer applies the URLSearchParams form encoding/content type and PHP-style integrations can receive an empty$_POST; treatcontentType: falseas another reason to retain and augment the original payload type.
const keepOriginalType = ajaxOptions && ajaxOptions.processData === false;
js/prebuild/apbct-public-bundle_ext-protection.js:4338
- jQuery skips its data serialization when
contentType: false, even ifprocessDataremains true. A recognizedURLSearchParamsrequest using that option is converted to a plain string below, so XHR no longer applies the URLSearchParams form encoding/content type and PHP-style integrations can receive an empty$_POST; treatcontentType: falseas another reason to retain and augment the original payload type.
const keepOriginalType = ajaxOptions && ajaxOptions.processData === false;
js/prebuild/apbct-public-bundle_full-protection.js:4338
- jQuery skips its data serialization when
contentType: false, even ifprocessDataremains true. A recognizedURLSearchParamsrequest using that option is converted to a plain string below, so XHR no longer applies the URLSearchParams form encoding/content type and PHP-style integrations can receive an empty$_POST; treatcontentType: falseas another reason to retain and augment the original payload type.
const keepOriginalType = ajaxOptions && ajaxOptions.processData === false;
js/prebuild/apbct-public-bundle_full-protection_gathering.js:4338
- jQuery skips its data serialization when
contentType: false, even ifprocessDataremains true. A recognizedURLSearchParamsrequest using that option is converted to a plain string below, so XHR no longer applies the URLSearchParams form encoding/content type and PHP-style integrations can receive an empty$_POST; treatcontentType: falseas another reason to retain and augment the original payload type.
const keepOriginalType = ajaxOptions && ajaxOptions.processData === false;
js/prebuild/apbct-public-bundle_gathering.js:4338
- jQuery skips its data serialization when
contentType: false, even ifprocessDataremains true. A recognizedURLSearchParamsrequest using that option is converted to a plain string below, so XHR no longer applies the URLSearchParams form encoding/content type and PHP-style integrations can receive an empty$_POST; treatcontentType: falseas another reason to retain and augment the original payload type.
const keepOriginalType = ajaxOptions && ajaxOptions.processData === false;
js/prebuild/apbct-public-bundle_int-protection.js:4338
- jQuery skips its data serialization when
contentType: false, even ifprocessDataremains true. A recognizedURLSearchParamsrequest using that option is converted to a plain string below, so XHR no longer applies the URLSearchParams form encoding/content type and PHP-style integrations can receive an empty$_POST; treatcontentType: falseas another reason to retain and augment the original payload type.
const keepOriginalType = ajaxOptions && ajaxOptions.processData === false;
js/prebuild/apbct-public-bundle_int-protection_gathering.js:4338
- jQuery skips its data serialization when
contentType: false, even ifprocessDataremains true. A recognizedURLSearchParamsrequest using that option is converted to a plain string below, so XHR no longer applies the URLSearchParams form encoding/content type and PHP-style integrations can receive an empty$_POST; treatcontentType: falseas another reason to retain and augment the original payload type.
const keepOriginalType = ajaxOptions && ajaxOptions.processData === false;
js/src/public-1-main.js:1591
- jQuery skips its data serialization when
contentType: false, even ifprocessDataremains true. A recognizedURLSearchParamsrequest using that option is converted to a plain string below, so XHR no longer applies the URLSearchParams form encoding/content type and PHP-style integrations can receive an empty$_POST; treatcontentType: falseas another reason to retain and augment the original payload type.
const keepOriginalType = ajaxOptions && ajaxOptions.processData === false;
- Files reviewed: 9/17 changed files
- Comments generated: 0 new
- Review effort level: Lite
There was a problem hiding this comment.
🟡 Changes recommended
URLSearchParams payloads with contentType: false can be emptied by jQuery while processData remains enabled.
Get a fresh assessment by requesting another Copilot review.
Review details
- Files reviewed: 9/17 changed files
- Comments generated: 9
- Review effort level: Lite
There was a problem hiding this comment.
🔵 Needs a closer look
Normalize nested and bracketed payload fields so valid AJAX requests receive CleanTalk data.
Review details
Suppressed comments (11)
js/prebuild/apbct-public-bundle.js:3992
- These branches only recognize top-level
action/nonce fields. A valid WordPress-style payload usingdata[action]=pafe_ajax_form_builderis either ignored bygetStructuredJQAjaxSignStringor encoded byURLSearchParams.toString()asdata%5Baction%5D=..., so the lateraction=...checks never match and no CleanTalk fields are injected. FormData already explicitly unwraps this samedata[...]shape; normalize equivalent object/URLSearchParams keys before sign matching.
if ( this.isJQAjaxPlainObjectOrArray(ajaxObject.data) ) {
return this.getStructuredJQAjaxSignString(ajaxObject.data);
}
if ( this.isJQAjaxURLSearchParams(ajaxObject.data) ) {
return ajaxObject.data.toString();
js/prebuild/apbct-public-bundle_ext-protection.js:3992
- These branches only recognize top-level
action/nonce fields. A valid WordPress-style payload usingdata[action]=pafe_ajax_form_builderis either ignored bygetStructuredJQAjaxSignStringor encoded byURLSearchParams.toString()asdata%5Baction%5D=..., so the lateraction=...checks never match and no CleanTalk fields are injected. FormData already explicitly unwraps this samedata[...]shape; normalize equivalent object/URLSearchParams keys before sign matching.
if ( this.isJQAjaxPlainObjectOrArray(ajaxObject.data) ) {
return this.getStructuredJQAjaxSignString(ajaxObject.data);
}
if ( this.isJQAjaxURLSearchParams(ajaxObject.data) ) {
return ajaxObject.data.toString();
js/prebuild/apbct-public-bundle_ext-protection_gathering.js:3992
- These branches only recognize top-level
action/nonce fields. A valid WordPress-style payload usingdata[action]=pafe_ajax_form_builderis either ignored bygetStructuredJQAjaxSignStringor encoded byURLSearchParams.toString()asdata%5Baction%5D=..., so the lateraction=...checks never match and no CleanTalk fields are injected. FormData already explicitly unwraps this samedata[...]shape; normalize equivalent object/URLSearchParams keys before sign matching.
if ( this.isJQAjaxPlainObjectOrArray(ajaxObject.data) ) {
return this.getStructuredJQAjaxSignString(ajaxObject.data);
}
if ( this.isJQAjaxURLSearchParams(ajaxObject.data) ) {
return ajaxObject.data.toString();
js/prebuild/apbct-public-bundle_full-protection.js:3992
- These branches only recognize top-level
action/nonce fields. A valid WordPress-style payload usingdata[action]=pafe_ajax_form_builderis either ignored bygetStructuredJQAjaxSignStringor encoded byURLSearchParams.toString()asdata%5Baction%5D=..., so the lateraction=...checks never match and no CleanTalk fields are injected. FormData already explicitly unwraps this samedata[...]shape; normalize equivalent object/URLSearchParams keys before sign matching.
if ( this.isJQAjaxPlainObjectOrArray(ajaxObject.data) ) {
return this.getStructuredJQAjaxSignString(ajaxObject.data);
}
if ( this.isJQAjaxURLSearchParams(ajaxObject.data) ) {
return ajaxObject.data.toString();
js/prebuild/apbct-public-bundle_full-protection_gathering.js:3992
- These branches only recognize top-level
action/nonce fields. A valid WordPress-style payload usingdata[action]=pafe_ajax_form_builderis either ignored bygetStructuredJQAjaxSignStringor encoded byURLSearchParams.toString()asdata%5Baction%5D=..., so the lateraction=...checks never match and no CleanTalk fields are injected. FormData already explicitly unwraps this samedata[...]shape; normalize equivalent object/URLSearchParams keys before sign matching.
if ( this.isJQAjaxPlainObjectOrArray(ajaxObject.data) ) {
return this.getStructuredJQAjaxSignString(ajaxObject.data);
}
if ( this.isJQAjaxURLSearchParams(ajaxObject.data) ) {
return ajaxObject.data.toString();
js/prebuild/apbct-public-bundle_gathering.js:3992
- These branches only recognize top-level
action/nonce fields. A valid WordPress-style payload usingdata[action]=pafe_ajax_form_builderis either ignored bygetStructuredJQAjaxSignStringor encoded byURLSearchParams.toString()asdata%5Baction%5D=..., so the lateraction=...checks never match and no CleanTalk fields are injected. FormData already explicitly unwraps this samedata[...]shape; normalize equivalent object/URLSearchParams keys before sign matching.
if ( this.isJQAjaxPlainObjectOrArray(ajaxObject.data) ) {
return this.getStructuredJQAjaxSignString(ajaxObject.data);
}
if ( this.isJQAjaxURLSearchParams(ajaxObject.data) ) {
return ajaxObject.data.toString();
js/prebuild/apbct-public-bundle_int-protection.js:3992
- These branches only recognize top-level
action/nonce fields. A valid WordPress-style payload usingdata[action]=pafe_ajax_form_builderis either ignored bygetStructuredJQAjaxSignStringor encoded byURLSearchParams.toString()asdata%5Baction%5D=..., so the lateraction=...checks never match and no CleanTalk fields are injected. FormData already explicitly unwraps this samedata[...]shape; normalize equivalent object/URLSearchParams keys before sign matching.
if ( this.isJQAjaxPlainObjectOrArray(ajaxObject.data) ) {
return this.getStructuredJQAjaxSignString(ajaxObject.data);
}
if ( this.isJQAjaxURLSearchParams(ajaxObject.data) ) {
return ajaxObject.data.toString();
js/prebuild/apbct-public-bundle_int-protection_gathering.js:3992
- These branches only recognize top-level
action/nonce fields. A valid WordPress-style payload usingdata[action]=pafe_ajax_form_builderis either ignored bygetStructuredJQAjaxSignStringor encoded byURLSearchParams.toString()asdata%5Baction%5D=..., so the lateraction=...checks never match and no CleanTalk fields are injected. FormData already explicitly unwraps this samedata[...]shape; normalize equivalent object/URLSearchParams keys before sign matching.
if ( this.isJQAjaxPlainObjectOrArray(ajaxObject.data) ) {
return this.getStructuredJQAjaxSignString(ajaxObject.data);
}
if ( this.isJQAjaxURLSearchParams(ajaxObject.data) ) {
return ajaxObject.data.toString();
js/src/public-1-main.js:1245
- These branches only recognize top-level
action/nonce fields. A valid WordPress-style payload usingdata[action]=pafe_ajax_form_builderis either ignored bygetStructuredJQAjaxSignStringor encoded byURLSearchParams.toString()asdata%5Baction%5D=..., so the lateraction=...checks never match and no CleanTalk fields are injected. FormData already explicitly unwraps this samedata[...]shape; normalize equivalent object/URLSearchParams keys before sign matching.
if ( this.isJQAjaxPlainObjectOrArray(ajaxObject.data) ) {
return this.getStructuredJQAjaxSignString(ajaxObject.data);
}
if ( this.isJQAjaxURLSearchParams(ajaxObject.data) ) {
return ajaxObject.data.toString();
js/src/public-1-main.js:1310
- A serializeArray entry can use a form-style name such as
data[twt_cc_signup]. The old serialized-string path matched that name, but this condition only accepts the exacttwt_cc_signupname (or a matching value), so the prefilter skips the request and does not inject CleanTalk data. Normalize bracketed names or matchtwt_cc_signupwithinentry.nametoo.
entry.name === 'action' ||
entry.name === 'ur_frontend_form_nonce' ||
entry.name === 'twt_cc_signup' ||
(typeof value === 'string' && value.indexOf('twt_cc_signup') !== -1)
js/src/public-1-main.js:1288
- This structural scan misses bracketed/nested field names such as
{'data[twt_cc_signup]': 1}. jQuery serializes that object to a payload containingtwt_cc_signup, which the previous string-based check detected, but this method only recognizes an exact top-level key or a string value. Such requests are therefore not recognized and receive no CleanTalk fields; match bracketed keys and/or recurse through nested objects as part of the structural scan.
for ( const key in data ) {
if ( !Object.prototype.hasOwnProperty.call(data, key) ) {
continue;
}
if ( typeof data[key] === 'string' && data[key].indexOf('twt_cc_signup') !== -1 ) {
return true;
- Files reviewed: 9/17 changed files
- Comments generated: 0 new
- Review effort level: Lite
There was a problem hiding this comment.
🔵 Needs a closer look
Moderate issues remain with base64 token encoding and entries() fallback handling.
Review details
Suppressed comments (16)
js/prebuild/apbct-public-bundle.js:4433
- These new object/URLSearchParams paths route payloads through
injectCleantalkDataToJQAjaxString, which prependsgetNoCookieData()verbatim. That value is base64, so a+is decoded as a space in anapplication/x-www-form-urlencodedrequest and the no-cookie token becomes invalid. URL-encode the value (or append it through a form encoder) before using this string path.
if ( typeof ajaxData === 'string' ) {
return this.injectCleantalkDataToJQAjaxString(sourceSign, ajaxData);
js/prebuild/apbct-public-bundle.js:4215
- This fallback handles only
get()afterforEach(). FormData polyfills can exposeentries()without either method (the previous implementation usedentries()for the visible-field path); for those payloadsdata[action]/actionis never discovered, so the prefilter skips CleanTalk injection entirely. Add anentries()enumeration fallback before returning an empty sign string.
if ( typeof bag.get !== 'function' ) {
return '';
}
js/prebuild/apbct-public-bundle_ext-protection.js:4433
- These new object/URLSearchParams paths route payloads through
injectCleantalkDataToJQAjaxString, which prependsgetNoCookieData()verbatim. That value is base64, so a+is decoded as a space in anapplication/x-www-form-urlencodedrequest and the no-cookie token becomes invalid. URL-encode the value (or append it through a form encoder) before using this string path.
if ( typeof ajaxData === 'string' ) {
return this.injectCleantalkDataToJQAjaxString(sourceSign, ajaxData);
js/prebuild/apbct-public-bundle_ext-protection.js:4215
- This fallback handles only
get()afterforEach(). FormData polyfills can exposeentries()without either method (the previous implementation usedentries()for the visible-field path); for those payloadsdata[action]/actionis never discovered, so the prefilter skips CleanTalk injection entirely. Add anentries()enumeration fallback before returning an empty sign string.
if ( typeof bag.get !== 'function' ) {
return '';
}
js/prebuild/apbct-public-bundle_ext-protection_gathering.js:4215
- This fallback handles only
get()afterforEach(). FormData polyfills can exposeentries()without either method (the previous implementation usedentries()for the visible-field path); for those payloadsdata[action]/actionis never discovered, so the prefilter skips CleanTalk injection entirely. Add anentries()enumeration fallback before returning an empty sign string.
if ( typeof bag.get !== 'function' ) {
return '';
}
js/prebuild/apbct-public-bundle_full-protection.js:4433
- These new object/URLSearchParams paths route payloads through
injectCleantalkDataToJQAjaxString, which prependsgetNoCookieData()verbatim. That value is base64, so a+is decoded as a space in anapplication/x-www-form-urlencodedrequest and the no-cookie token becomes invalid. URL-encode the value (or append it through a form encoder) before using this string path.
if ( typeof ajaxData === 'string' ) {
return this.injectCleantalkDataToJQAjaxString(sourceSign, ajaxData);
js/prebuild/apbct-public-bundle_full-protection.js:4215
- This fallback handles only
get()afterforEach(). FormData polyfills can exposeentries()without either method (the previous implementation usedentries()for the visible-field path); for those payloadsdata[action]/actionis never discovered, so the prefilter skips CleanTalk injection entirely. Add anentries()enumeration fallback before returning an empty sign string.
if ( typeof bag.get !== 'function' ) {
return '';
}
js/prebuild/apbct-public-bundle_full-protection_gathering.js:4215
- This fallback handles only
get()afterforEach(). FormData polyfills can exposeentries()without either method (the previous implementation usedentries()for the visible-field path); for those payloadsdata[action]/actionis never discovered, so the prefilter skips CleanTalk injection entirely. Add anentries()enumeration fallback before returning an empty sign string.
if ( typeof bag.get !== 'function' ) {
return '';
}
js/prebuild/apbct-public-bundle_gathering.js:4433
- These new object/URLSearchParams paths route payloads through
injectCleantalkDataToJQAjaxString, which prependsgetNoCookieData()verbatim. That value is base64, so a+is decoded as a space in anapplication/x-www-form-urlencodedrequest and the no-cookie token becomes invalid. URL-encode the value (or append it through a form encoder) before using this string path.
if ( typeof ajaxData === 'string' ) {
return this.injectCleantalkDataToJQAjaxString(sourceSign, ajaxData);
js/prebuild/apbct-public-bundle_gathering.js:4215
- This fallback handles only
get()afterforEach(). FormData polyfills can exposeentries()without either method (the previous implementation usedentries()for the visible-field path); for those payloadsdata[action]/actionis never discovered, so the prefilter skips CleanTalk injection entirely. Add anentries()enumeration fallback before returning an empty sign string.
if ( typeof bag.get !== 'function' ) {
return '';
}
js/prebuild/apbct-public-bundle_int-protection.js:4433
- These new object/URLSearchParams paths route payloads through
injectCleantalkDataToJQAjaxString, which prependsgetNoCookieData()verbatim. That value is base64, so a+is decoded as a space in anapplication/x-www-form-urlencodedrequest and the no-cookie token becomes invalid. URL-encode the value (or append it through a form encoder) before using this string path.
if ( typeof ajaxData === 'string' ) {
return this.injectCleantalkDataToJQAjaxString(sourceSign, ajaxData);
js/prebuild/apbct-public-bundle_int-protection.js:4215
- This fallback handles only
get()afterforEach(). FormData polyfills can exposeentries()without either method (the previous implementation usedentries()for the visible-field path); for those payloadsdata[action]/actionis never discovered, so the prefilter skips CleanTalk injection entirely. Add anentries()enumeration fallback before returning an empty sign string.
if ( typeof bag.get !== 'function' ) {
return '';
}
js/prebuild/apbct-public-bundle_int-protection_gathering.js:4433
- These new object/URLSearchParams paths route payloads through
injectCleantalkDataToJQAjaxString, which prependsgetNoCookieData()verbatim. That value is base64, so a+is decoded as a space in anapplication/x-www-form-urlencodedrequest and the no-cookie token becomes invalid. URL-encode the value (or append it through a form encoder) before using this string path.
if ( typeof ajaxData === 'string' ) {
return this.injectCleantalkDataToJQAjaxString(sourceSign, ajaxData);
js/prebuild/apbct-public-bundle_int-protection_gathering.js:4215
- This fallback handles only
get()afterforEach(). FormData polyfills can exposeentries()without either method (the previous implementation usedentries()for the visible-field path); for those payloadsdata[action]/actionis never discovered, so the prefilter skips CleanTalk injection entirely. Add anentries()enumeration fallback before returning an empty sign string.
if ( typeof bag.get !== 'function' ) {
return '';
}
js/src/public-1-main.js:1686
- These new object/URLSearchParams paths route payloads through
injectCleantalkDataToJQAjaxString, which prependsgetNoCookieData()verbatim. That value is base64, so a+is decoded as a space in anapplication/x-www-form-urlencodedrequest and the no-cookie token becomes invalid. URL-encode the value (or append it through a form encoder) before using this string path.
if ( typeof ajaxData === 'string' ) {
return this.injectCleantalkDataToJQAjaxString(sourceSign, ajaxData);
js/src/public-1-main.js:1468
- This fallback handles only
get()afterforEach(). FormData polyfills can exposeentries()without either method (the previous implementation usedentries()for the visible-field path); for those payloadsdata[action]/actionis never discovered, so the prefilter skips CleanTalk injection entirely. Add anentries()enumeration fallback before returning an empty sign string.
if ( typeof bag.get !== 'function' ) {
return '';
}
- Files reviewed: 9/17 changed files
- Comments generated: 0 new
- Review effort level: Lite
There was a problem hiding this comment.
🔵 Needs a closer look
Four moderate AJAX payload-handling issues remain unresolved.
Review details
Suppressed comments (4)
js/src/public-1-main.js:1713
- This preserves object-like payloads whenever
processDataorcontentTypeis false, but the prefilter also handles GET/HEAD requests. jQuery only moves no-content data into the URL when it is a string orprocessDatais true; with this flag a recognized plain object, serializeArray, or URLSearchParams remains an object and the transport sends neither its original fields nor the injected CleanTalk fields. Exclude GET/HEAD (the default method when no type is supplied) fromkeepOriginalTypeso those payloads are serialized to the query string.
const keepOriginalType = !!(ajaxOptions && (
ajaxOptions.processData === false ||
ajaxOptions.contentType === false
));
js/src/public-1-main.js:1755
- This branch always forces
processData = falsefor FormData, including GET/HEAD requests. jQuery does not append a non-stringdatavalue to the URL for no-content methods, and its transport sends no body, so a recognized FormData request loses both the caller's fields and the injected CleanTalk fields. No-content requests need a query-string representation (or an explicit unsupported-case path) instead of preserving FormData.
if ( this.isJQAjaxFormData(ajaxData) ) {
this.preserveJQAjaxFormDataOptions(ajaxOptions);
return this.injectCleantalkDataToJQAjaxFormData(
js/src/public-1-main.js:1913
forEachJQAjaxKeyValueBag()explicitly supports FormData implementations that expose onlyentries(), but this clone path returns the original object wheneverforEach()is absent. For an entries-only FormData, the subsequentappend()calls therefore mutate the caller's payload; reusing that FormData for another AJAX request accumulates CleanTalk fields (and can send duplicates). Clone via the sameentries()fallback before appending, or otherwise avoid mutating the original when it is enumerable.
cloneFormData(formData) {
if ( typeof formData.forEach !== 'function' ) {
return formData;
}
js/src/public-1-main.js:1432
- The implementation below supports
entries()-only key/value bags, but this type guard rejects an entries-only FormData polyfill unless it happens to spoof[object FormData]. Such payloads fall through as unknown objects, so their action is not detected and no CleanTalk fields are injected. Includeentries()in the fallback capability check (while retaining the existing exclusions for URLSearchParams/Headers).
return typeof data.forEach === 'function' || typeof data.get === 'function';
- Files reviewed: 9/17 changed files
- Comments generated: 0 new
- Review effort level: Lite
There was a problem hiding this comment.
🔵 Needs a closer look
Moderate issues remain with WooCommerce token handling and IE11 FormData support.
Review details
Suppressed comments (12)
js/prebuild/apbct-public-bundle.js:4443
- For a GET/HEAD request to
wc-ajax=add_to_cart,keepUnwrappedremains false, so the dispatcher addsdata[ct_bot_detector_event_token]to the URL. WooCommerce's classic handler reads this token from top-levelGet::get('ct_bot_detector_event_token')(lib/Cleantalk/Antispam/IntegrationsByClass/Woocommerce.php:430-434), so it ignores the injected token; use unwrapped keys for no-body methods while retaining wrapped keys for POST payloads.
// woocommerce add to cart is based on URL
if ( typeof ajaxObject.url === 'string' && ajaxObject.url.indexOf('wc-ajax=add_to_cart') !== -1 ) {
sourceSign.found = 'wc-ajax=add_to_cart';
}
js/prebuild/apbct-public-bundle.js:4212
- Native IE11 FormData has no
forEach,entries, orget, so this branch returns an empty sign string for every such payload. As a result, action- andtwt_cc_signup-based requests are never recognized and receive no CleanTalk fields;getFormDataFieldcannot help because it runs only after a sign is found. Use a request/plugin signal that IE11 can inspect or remove the IE11 compatibility claim instead of relying on unavailable FormData readers.
if ( typeof bag.get !== 'function' ) {
return '';
js/prebuild/apbct-public-bundle_ext-protection.js:4443
- For a GET/HEAD request to
wc-ajax=add_to_cart,keepUnwrappedremains false, so the dispatcher addsdata[ct_bot_detector_event_token]to the URL. WooCommerce's classic handler reads this token from top-levelGet::get('ct_bot_detector_event_token')(lib/Cleantalk/Antispam/IntegrationsByClass/Woocommerce.php:430-434), so it ignores the injected token; use unwrapped keys for no-body methods while retaining wrapped keys for POST payloads.
// woocommerce add to cart is based on URL
if ( typeof ajaxObject.url === 'string' && ajaxObject.url.indexOf('wc-ajax=add_to_cart') !== -1 ) {
sourceSign.found = 'wc-ajax=add_to_cart';
}
js/prebuild/apbct-public-bundle_ext-protection.js:4212
- Native IE11 FormData has no
forEach,entries, orget, so this branch returns an empty sign string for every such payload. As a result, action- andtwt_cc_signup-based requests are never recognized and receive no CleanTalk fields;getFormDataFieldcannot help because it runs only after a sign is found. Use a request/plugin signal that IE11 can inspect or remove the IE11 compatibility claim instead of relying on unavailable FormData readers.
if ( typeof bag.get !== 'function' ) {
return '';
js/prebuild/apbct-public-bundle_full-protection.js:4443
- For a GET/HEAD request to
wc-ajax=add_to_cart,keepUnwrappedremains false, so the dispatcher addsdata[ct_bot_detector_event_token]to the URL. WooCommerce's classic handler reads this token from top-levelGet::get('ct_bot_detector_event_token')(lib/Cleantalk/Antispam/IntegrationsByClass/Woocommerce.php:430-434), so it ignores the injected token; use unwrapped keys for no-body methods while retaining wrapped keys for POST payloads.
// woocommerce add to cart is based on URL
if ( typeof ajaxObject.url === 'string' && ajaxObject.url.indexOf('wc-ajax=add_to_cart') !== -1 ) {
sourceSign.found = 'wc-ajax=add_to_cart';
}
js/prebuild/apbct-public-bundle_full-protection.js:4212
- Native IE11 FormData has no
forEach,entries, orget, so this branch returns an empty sign string for every such payload. As a result, action- andtwt_cc_signup-based requests are never recognized and receive no CleanTalk fields;getFormDataFieldcannot help because it runs only after a sign is found. Use a request/plugin signal that IE11 can inspect or remove the IE11 compatibility claim instead of relying on unavailable FormData readers.
if ( typeof bag.get !== 'function' ) {
return '';
js/prebuild/apbct-public-bundle_gathering.js:4443
- For a GET/HEAD request to
wc-ajax=add_to_cart,keepUnwrappedremains false, so the dispatcher addsdata[ct_bot_detector_event_token]to the URL. WooCommerce's classic handler reads this token from top-levelGet::get('ct_bot_detector_event_token')(lib/Cleantalk/Antispam/IntegrationsByClass/Woocommerce.php:430-434), so it ignores the injected token; use unwrapped keys for no-body methods while retaining wrapped keys for POST payloads.
// woocommerce add to cart is based on URL
if ( typeof ajaxObject.url === 'string' && ajaxObject.url.indexOf('wc-ajax=add_to_cart') !== -1 ) {
sourceSign.found = 'wc-ajax=add_to_cart';
}
js/prebuild/apbct-public-bundle_gathering.js:4212
- Native IE11 FormData has no
forEach,entries, orget, so this branch returns an empty sign string for every such payload. As a result, action- andtwt_cc_signup-based requests are never recognized and receive no CleanTalk fields;getFormDataFieldcannot help because it runs only after a sign is found. Use a request/plugin signal that IE11 can inspect or remove the IE11 compatibility claim instead of relying on unavailable FormData readers.
if ( typeof bag.get !== 'function' ) {
return '';
js/prebuild/apbct-public-bundle_int-protection.js:4443
- For a GET/HEAD request to
wc-ajax=add_to_cart,keepUnwrappedremains false, so the dispatcher addsdata[ct_bot_detector_event_token]to the URL. WooCommerce's classic handler reads this token from top-levelGet::get('ct_bot_detector_event_token')(lib/Cleantalk/Antispam/IntegrationsByClass/Woocommerce.php:430-434), so it ignores the injected token; use unwrapped keys for no-body methods while retaining wrapped keys for POST payloads.
// woocommerce add to cart is based on URL
if ( typeof ajaxObject.url === 'string' && ajaxObject.url.indexOf('wc-ajax=add_to_cart') !== -1 ) {
sourceSign.found = 'wc-ajax=add_to_cart';
}
js/prebuild/apbct-public-bundle_int-protection.js:4212
- Native IE11 FormData has no
forEach,entries, orget, so this branch returns an empty sign string for every such payload. As a result, action- andtwt_cc_signup-based requests are never recognized and receive no CleanTalk fields;getFormDataFieldcannot help because it runs only after a sign is found. Use a request/plugin signal that IE11 can inspect or remove the IE11 compatibility claim instead of relying on unavailable FormData readers.
if ( typeof bag.get !== 'function' ) {
return '';
js/src/public-1-main.js:1696
- For a GET/HEAD request to
wc-ajax=add_to_cart,keepUnwrappedremains false, so the dispatcher addsdata[ct_bot_detector_event_token]to the URL. WooCommerce's classic handler reads this token from top-levelGet::get('ct_bot_detector_event_token')(lib/Cleantalk/Antispam/IntegrationsByClass/Woocommerce.php:430-434), so it ignores the injected token; use unwrapped keys for no-body methods while retaining wrapped keys for POST payloads.
// woocommerce add to cart is based on URL
if ( typeof ajaxObject.url === 'string' && ajaxObject.url.indexOf('wc-ajax=add_to_cart') !== -1 ) {
sourceSign.found = 'wc-ajax=add_to_cart';
}
js/src/public-1-main.js:1465
- Native IE11 FormData has no
forEach,entries, orget, so this branch returns an empty sign string for every such payload. As a result, action- andtwt_cc_signup-based requests are never recognized and receive no CleanTalk fields;getFormDataFieldcannot help because it runs only after a sign is found. Use a request/plugin signal that IE11 can inspect or remove the IE11 compatibility claim instead of relying on unavailable FormData readers.
if ( typeof bag.get !== 'function' ) {
return '';
- Files reviewed: 9/17 changed files
- Comments generated: 0 new
- Review effort level: Lite
There was a problem hiding this comment.
🔵 Needs a closer look
The AJAX interception and regenerated bundle changes span multiple payload formats and integrations, warranting human review.
Review details
- Files reviewed: 9/17 changed files
- Comments generated: 0 new
- Review effort level: Lite
task https://app.doboard.com/1/task/44016