Specifications
What the plugin writes, when it writes it, under which rules, and what can be plugged into it.
Requirements
| Item | Requirement | Note |
|---|---|---|
| WordPress | 6.0 or later | Proven up to 7.1 |
| WooCommerce | 8.0 or later | Proven up to 10.9 |
| PHP | 8.0 or later | Full test pass on 8.0, 8.2, 8.3 and 8.4 |
| Order storage | HPOS or wp_posts | Both, with identical counts |
| Multilingual | WPML-friendly | Values are stored in English, translated on display |
| Multi-currency | yes | The currency is read from each order, never assumed |
| Interface languages | English, French | Any other from the supplied .pot |
| Capability | manage_woocommerce | Checked at menu registration and at render |
No value is hard-coded in the plugin file. It installs on any shop without a line being touched. Only the conversion action name must be set before the first export.
Capture
| Hook | Role |
|---|---|
woocommerce_checkout_order_created | Capture at classic checkout, priority 5 |
woocommerce_store_api_checkout_order_processed | Capture at block checkout |
woocommerce_thankyou | Second reading, for consent granted mid-journey |
| Meta | Content |
|---|---|
_neant_gcl_aw | Raw _gcl_aw cookie, of the form GCL.<timestamp>.<gclid> |
_neant_gcl_gb | _gcl_gb cookie — iOS traffic, gbraid |
_neant_gcl_au | yes / no |
_neant_consent | yes, no, unknown, undetected |
_neant_ty_gcl_aw, _neant_ty_consent | Thank-you page reading |
_neant_gads_exported_at, …_export_batch | Export timestamp and batch |
_neant_gads_adjusted_at, …_adjust_batch, …_adjust_type | Adjustment sent |
Capture writes even when no cookie is present. An order without
_neant_consent means "capture did not run"; an order with an empty
_neant_gcl_aw means "no Ads click". Conflating the two would make an
interrupted collection indistinguishable from a month without Ads traffic.
Rules
An order goes out if every condition holds.
| Ref. | Condition | Reason if not met |
|---|---|---|
| E0 | Capture ran | no capture |
| E1 | Click identifier present and parsable | no gclid |
| E2 | Identifier not already retained in the batch | duplicate of #… |
| E3 | Status in the configured list | status … excluded |
| E4 | Amount strictly positive | zero value |
| E5a | Order within the window following the click | order outside the click window |
| E5b | Click still importable today | click older than 90 days |
| E6 | Not already exported | already exported on … |
E2 is judged among the orders that are otherwise exportable. If the older of two orders sharing an identifier is cancelled, the next one takes its place — otherwise the conversion would be lost between the two. At equal dates the order ID decides, so that two exports of the same batch retain the same row.
Consent does not enter these rules. It is displayed, never applied.
| Ref. | Condition | Result |
|---|---|---|
| A1 | Conversion already exported | otherwise, nothing to adjust |
| A2 | Status now cancelled, refunded, failed | RETRACT |
| A3 | Refund covering the whole amount | RETRACT, whatever the status |
| A4 | Partial refund | RESTATE on the remainder |
| A5 | Conversion older than 24 h | otherwise too recent |
| A6 | Conversion younger than 54 days | otherwise outside the adjustment window |
| A7 | No adjustment already sent | except escalating RESTATE → RETRACT |
A7 allows escalation in one direction only. A partial refund followed by a cancellation is common, and stopping at the first adjustment would leave the conversion counted for the remainder. The reverse is impossible: Google is explicit that a retracted conversion can no longer be adjusted.
Formats
Parameters:TimeZone=Europe/Brussels "Google Click ID","Conversion Name","Conversion Time","Conversion Value","Conversion Currency","Order ID" Cj0KCQjw…,Achat - import hors connexion,2026-07-31 07:46:18+02:00,335.00,EUR,66658
Order ID is optional for Google and decisive here: it is the recommended key for
attaching a later adjustment. Without it, a retraction would rest on the identifier +
timestamp pair, which the slightest time-zone drift misaligns.
"Order ID","Conversion Name","Adjustment Time","Adjustment Type","Adjusted Value","Adjusted Value Currency" 66658,Achat - import hors connexion,2026-09-12 14:22:03+02:00,RETRACT,, 66643,Achat - import hors connexion,2026-09-03 09:15:41+02:00,RESTATE,150.00,EUR
This file carries no Parameters:TimeZone= line: the zone is
declared in each Adjustment Time. A retraction leaves value and currency empty —
writing a zero there would read as a restatement to zero.
The two windows differ: 90 days to import from the click, 54 days to adjust from the conversion, of which 7 for bidding to take it into account. A conversion imported late can be born irretractable.
Consent
The advertising consent state is read from the site's own banner. The first adapter whose cookie answers wins.
| Platform | Signal | Reading |
|---|---|---|
| CookieYes | cookieyes-consent | advertisement:yes / :no |
| Complianz | cmplz_marketing | allow / deny |
| Axeptio | axeptio_authorized_vendors | advertising vendor in the authorised list |
| Borlabs Cookie | borlabs-cookie | marketing category not empty |
undetected and no are never conflated. One says
the person refused, the other that the tool cannot read this banner. Collapsing them onto a
single value would produce a column that looks informative while merely recording its own
blindness.
Extending
| Filter | Use |
|---|---|
neant_gads_consent_adapters | Plug in a custom adapter. Placed first, it wins over the shipped ones. |
neant_gads_axeptio_ad_vendors | Adapt the site's Axeptio vendor naming. |
neant_gads_root_menu_label | Rename the root entry in the admin menu. |
| Item | Value |
|---|---|
| Route | /wp-json/neant-gads/v1/adjustments.csv |
| Authentication | Basic, constant-time comparison |
| Transport | HTTPS required, re-checked on every call |
| Rate limit | 30 requests per hour per address |
| Scope | Fixed server-side, never driven by the URL |
| HEAD request | Served dry: it does not consume the queue |
English is the source language. French ships with the plugin. Any other language is added by
translating languages/neant-gads-offline.pot with Poedit or Loco Translate — no
PHP involved. Regional variants fall back to the closest available translation of the same
language, so an fr_CA site is not left in English for want of a catalogue in its
own name.
Options and the scheduled task are removed. No order metadata is deleted: it is the only trace of recoverable conversions, and an uninstall by mistake would make them permanently unrecoverable. The cost of a leftover row is nil; the cost of a deletion is not.