Skip to content

Commit a2cdc59

Browse files
Release 2.5.15 — sanitized sync (page-context tracking and save-test prune)
Port signed public page_context tokens, selector-proxy redirect lock-down, and deferred variant pruning from ElementTest-WP 2.5.14 while keeping Doug Wagner authorship and this repository as the update source. Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 230f432 commit a2cdc59

7 files changed

Lines changed: 483 additions & 45 deletions

File tree

‎CHANGELOG.md‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,14 @@
22

33
`readme.txt` remains the canonical WordPress.org release history for this plugin. This file mirrors the shipped release notes in a GitHub-friendly format.
44

5+
## 2.5.15
6+
7+
> Public tracking page-context hardening and selector-proxy redirect lock-down, plus admin save-test variant prune reorder so goal validation failures cannot delete variants. Ported from ElementTest-WP 2.5.14 (PRs #7 and #11). JS `VERSION` synced to 2.5.15.
8+
9+
- Fix: **Signed `page_context` tokens** for public assignment, impression, and conversion writes. PHP embeds a signed token (test ID, server-observed URL, expiry) in localized payloads; the frontend sends it on tracking calls. Public write endpoints verify the token and scope writes to the rendered page. Pageview conversions are matched against the stored goal trigger instead of posted `page_url`.
10+
- Fix: **Admin selector proxy** uses `wp_safe_remote_get()`, disables redirects, and rejects 3xx responses.
11+
- Fix: **Variant pruning deferred** until after conversion-goal validation and persistence in `save_test()`, so a failed goal save cannot delete omitted variants.
12+
513
## 2.5.14
614

715
> Plugin author set to Doug Wagner. JS `VERSION` synced to 2.5.14.

‎README.md‎

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,50 @@ Ready-to-install zip builds are published on [GitHub Releases](https://github.co
2525
- Performance analytics with statistical significance
2626
- Schedule-based test start/stop
2727
- Export reports as standalone HTML (with Chart.js visual dashboard), CSV, or JSON via admin UI or WP-CLI
28+
- Admin-only forced-variant preview URLs for QA
29+
- WP-CLI repair command for legacy JS/CSS variant source mangling
2830
- Optional GA4 custom event forwarding for variant conversions (fires `elementtest_converted` to your existing `gtag` tag in parallel with the plugin's DB tracking)
2931

32+
## Developer and QA Workflows
33+
34+
### Previewing a specific variant as an admin
35+
36+
Logged-in admins can force the frontend assignment endpoint to return a specific variant for visual QA without waiting on random traffic allocation:
37+
38+
```text
39+
https://example.com/product/my-page/?et_force=control
40+
https://example.com/product/my-page/?et_force=123
41+
```
42+
43+
- `control` selects the control variant for every running test on the page.
44+
- A numeric value selects the matching `wp_elementtest_variants.variant_id` for that test.
45+
- The override is gated by `current_user_can( 'manage_options' )`; anonymous visitors and non-admin users ignore the query parameter and stay on the normal weighted assignment path.
46+
- The request still goes through `elementtest_get_variant_assignment`, page-scope validation, the normal `elementtest_variant_<test_id>` browser cookie, and the HttpOnly assignment-proof cookie. Use a clean browser/profile when you need to test organic random assignment after forcing variants.
47+
- Production admin preview traffic can still create impressions through the normal tracking flow. Prefer staging for repeated QA passes, or account for admin visits when reviewing report data.
48+
49+
### Repairing pre-2.4.2 JS/CSS variant source
50+
51+
Before 2.4.2, variant `changes` were sanitized with `wp_kses_post()` regardless of test type. For `js` and `css` tests this could encode operators and selectors (`>=` to `&gt;=`, `&&` to `&amp;&amp;`, `.a > .b` to `.a &gt; .b`) so variants either threw JavaScript syntax errors or CSS silently failed to match.
52+
53+
Use the WP-CLI repair command to inspect and optionally decode affected rows:
54+
55+
```bash
56+
# Dry-run scan of all JS/CSS variants. No database writes.
57+
wp elementtest fix-variant-changes
58+
59+
# Show compact diffs for JavaScript variants only.
60+
wp elementtest fix-variant-changes --type=js --show-diff
61+
62+
# Repair with a JSON backup of original rows.
63+
wp elementtest fix-variant-changes --apply \
64+
--backup=variants-backup-$(date +%Y%m%d).json
65+
66+
# Limit the repair to one test.
67+
wp elementtest fix-variant-changes --test-id=6 --apply --backup=t6.json
68+
```
69+
70+
The command decodes only the five entity fingerprints produced by the old sanitizer (`&amp;`, `&lt;`, `&gt;`, `&quot;`, `&#039;`/`&#39;`). Other named entities such as `&nbsp;` and `&copy;` are left intact because they may be intentional inside HTML strings.
71+
3072
## Database Tables
3173

3274
The plugin creates the following tables (prefixed with the WordPress table prefix):

‎assets/js/frontend.js‎

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ try {
3131
// Constants & State
3232
// =========================================================================
3333

34-
var VERSION = '2.5.14';
34+
var VERSION = '2.5.15';
3535
var OBSERVER_TIMEOUT = 8000; // Max time (ms) to wait for elements via MutationObserver.
3636
var ANTIFLICKER_TIMEOUT = 3000; // Max time (ms) before forcing anti-flicker removal.
3737

@@ -161,6 +161,29 @@ try {
161161
return null;
162162
}
163163

164+
/**
165+
* Find the signed page-context token for a test.
166+
*
167+
* @param {number} testId Test ID.
168+
* @return {string} Signed page-context token, or an empty string.
169+
*/
170+
function findPageContext( testId ) {
171+
var sources = [
172+
elementtestFrontend.tests || [],
173+
elementtestFrontend.conversionOnlyTests || []
174+
];
175+
176+
for ( var s = 0; s < sources.length; s++ ) {
177+
for ( var i = 0; i < sources[ s ].length; i++ ) {
178+
if ( String( sources[ s ][ i ].test_id ) === String( testId ) ) {
179+
return sources[ s ][ i ].page_context || '';
180+
}
181+
}
182+
}
183+
184+
return '';
185+
}
186+
164187
/**
165188
* Request a server-authoritative assignment and proof cookie.
166189
*
@@ -177,7 +200,8 @@ try {
177200
nonce: elementtestFrontend.nonce,
178201
test_id: test.test_id,
179202
user_hash: elementtestFrontend.userHash,
180-
page_url: window.location.href
203+
page_url: window.location.href,
204+
page_context: test.page_context || ''
181205
};
182206

183207
if ( elementtestFrontend.isAdmin ) {
@@ -434,7 +458,8 @@ try {
434458
nonce: elementtestFrontend.nonce,
435459
test_id: testId,
436460
variant_id: variantId,
437-
user_hash: elementtestFrontend.userHash
461+
user_hash: elementtestFrontend.userHash,
462+
page_context: findPageContext( testId )
438463
};
439464

440465
sendTrackingRequest( data );
@@ -474,7 +499,8 @@ try {
474499
user_hash: elementtestFrontend.userHash,
475500
conversion_id: conversionId,
476501
revenue: revenue || 0,
477-
page_url: window.location.href
502+
page_url: window.location.href,
503+
page_context: findPageContext( testId )
478504
};
479505

480506
sendTrackingRequest( data );
@@ -1461,6 +1487,7 @@ try {
14611487
conversion_id: conversionId,
14621488
revenue: revenue || 0,
14631489
page_url: window.location.href,
1490+
page_context: findPageContext( testId ),
14641491
product_id: productId || '',
14651492
product_name: productName || '',
14661493
product_qty: productQty || 1

‎elementtest-pro.php‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* Plugin Name: ElementTest Pro
44
* Plugin URI: https://github.com/DougState/elementtest-pro
55
* Description: A/B test various elements (CSS, copy, JS, images) of your pages and track conversion data to measure performance.
6-
* Version: 2.5.14
6+
* Version: 2.5.15
77
* Requires at least: 5.6
88
* Tested up to: 7.0
99
* Requires PHP: 7.4
@@ -23,7 +23,7 @@
2323
}
2424

2525
// Define plugin constants
26-
define( 'ELEMENTTEST_VERSION', '2.5.14' );
26+
define( 'ELEMENTTEST_VERSION', '2.5.15' );
2727
define( 'ELEMENTTEST_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
2828
define( 'ELEMENTTEST_PLUGIN_URL', plugin_dir_url( __FILE__ ) );
2929
define( 'ELEMENTTEST_PLUGIN_BASENAME', plugin_basename( __FILE__ ) );

0 commit comments

Comments
 (0)