=== Datalayer Tracking via DATA Reshape for WooCommerce ===
Contributors: rwky
Donate link: https://www.paypal.me/eduardvd
Tags: datareshape, first-party-tracking, datalayer-tracking, woocommerce-tracking
Requires at least: 6.0
Tested up to: 7.0
Requires PHP: 7.4
WC requires at least: 8.2
WC tested up to: 11.0
Stable tag: 1.0.5
Requires Plugins: woocommerce
WC HPOS compatible: yes
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Official WooCommerce integration for DATA Reshape — first-party ecommerce event tracking delivered from your own subdomain.

== Description ==

DATA Reshape for WooCommerce is a bridge between your WooCommerce store and the DATA Reshape platform. It emits structured ecommerce events (`product_viewed`, `product_added_to_cart`, `cart_viewed`, `checkout_started`, `checkout_completed`, plus the mid-funnel checkout steps) into DATA Reshape's `reshape.push()` queue, and DATA Reshape's loader — served from a tracking subdomain you control — handles delivery and routing onward to GA4, Meta, TikTok, and every other destination you have connected.

Because the loader is served first-party, events are not blocked by ad blockers, ITP, or the usual third-party-script defences that break conventional `gtag`/`fbq`/`ttq` setups. You do not need to fire those calls in parallel — DATA Reshape routes a single event to every connected destination with the correct platform-specific name and field mapping.

This plugin does not replace analytics tools like Google Analytics or Meta Pixel; it replaces the *fragile transport layer* underneath them. Event processing, routing, and deduplication all happen inside DATA Reshape.

An active [DATA Reshape](https://datareshape.ro) plan is required to use this plugin. All tracking logic, integrations, and event delivery are managed through the DATA Reshape platform.

= Server-side order webhook (API Events) =

The "API Events" tab sends a server-to-server order webhook straight from your store to DATA Reshape. It exists to cover what the browser physically can't: off-site payment gateways that confirm the order minutes or hours later (or where the shopper never returns to the thank-you page), and phone/admin-created orders that never had a browser session. The `checkout_completed` webhook uses the order number as its event ID, so DATA Reshape reconciles it with the browser purchase event — if one signal is missing the other fills in, with no double counting. An `order_canceled` event covers cancellations and refunds, and a Test mode validates real order payloads against DATA Reshape's `/test` endpoint before you go live.

== Features ==

= Core Features =
- Global enable/disable for the integration
- DATA Reshape library integration
- Subdomain tracking support
- Fully compatible with WooCommerce HPOS (High-Performance Order Storage)

= Events =
- Product Viewed
- Product Added to Cart (AJAX + POST + GET fallbacks)
- Product Removed from Cart
- Cart Viewed
- Checkout Started
- Checkout Steps (Billing Address Added, Shipping Detail Added, Payment Method Selected — legacy checkout only)
- Checkout Completed
- Consent integration — DATA Reshape natively detects most CMPs (Cookiebot, OneTrust, Termly, etc.) and Google Consent Mode v2, with no plugin-side wiring required
- Single "Grant consent by default" toggle for stores that don't run a CMP — fires DATA Reshape's native `consent_updated` push at session start so events process immediately
- `drswc_consent_payload` filter for stores that want to drive the consent object explicitly from PHP
- Plain user data in reshape payloads (DATA Reshape hashes server-side)

= API Events (Server-side) =
- Server-to-server order webhook to DATA Reshape's `/webhooks/wordpress/event` endpoint
- Fires on a configurable order status (default Processing; pick any status your flow reaches, including custom statuses)
- Covers off-site gateway returns (confirmed minutes/hours later, or the shopper never returns) and phone/admin orders with no browser session
- `checkout_completed` uses the order number as event ID so DATA Reshape deduplicates it against the browser purchase event
- `order_canceled` event on Cancelled / Refunded orders
- Relays DATA Reshape's first-party `drespa` cookie captured on the order at checkout
- Test mode routes payloads to the `/test` validation endpoint and surfaces errors/warnings in the admin
- Optional activity log (WooCommerce-native, source `drswc-webhook`) with an in-admin Logs tab for setup debugging
- `drswc_webhook_payload` filter to customize the outgoing envelope

= Advanced Tracking =
- Spec-shaped products with `price_base` + `price`; `tax_included` / `tax_percent` only when WooCommerce tax is enabled
- Variations carry `parent_id` / `parent_name` / `parent_sku` / `parent_url`
- Order-level and product-level coupons emitted in dedicated `coupons[]` arrays
- Shipping methods and payment methods emitted as structured arrays on Checkout Completed
- Categories emitted as both `category` (primary) and `categories[]` with `name`+`id`
- Stock status, product type, creation timestamp, image, and gallery images

= Extensibility =
- `drswc_event_payload` — filter the full event envelope before push
- `drswc_product_payload` — inject GTIN/MPN/EAN, predicted values, custom properties per product
- `drswc_user_payload` — augment user identity (`pre_purchase` or `purchase` source)
- `drswc_consent_payload` — replace or inject the consent object
- `drswc_webhook_payload` — customize the server-side order webhook envelope

= Reliability Enhancements =
- Handles non-AJAX add-to-cart flows
- Handles redirect-based add-to-cart (?add-to-cart=)
- Cache-safe identity hydration — PII never inlined into cacheable HTML
- Sticky user identity model (loader caches first-seen user, subsequent events inherit)
- Safe execution timing for low overhead

== Installation ==

1. Upload the plugin to the `/wp-content/plugins/` directory
2. Activate the plugin through the 'Plugins' screen in WordPress
3. Ensure WooCommerce is installed and active
4. Open the settings from either **WooCommerce → Settings → DATA Reshape** or **Marketing → DATA Reshape** (the page lives under WooCommerce Settings; the Marketing entry is a shortcut)
5. Fill in your tracking subdomain and library ID (provided by DATA Reshape), enable the integration, and turn on the events you want emitted

== Configuration ==

= Integration Setup =
- Enable Integration (master switch)
- Tracking Subdomain (the first-party host serving DATA Reshape's loader)
- Library ID
- Built-in "Check tracking endpoint" health check
- Access token (credential for the API Events order webhook; the webhook reuses your Tracking subdomain and Library ID)

= Events =
- Master switch for browser-delivered events
- Per-event toggles (so events you handle via custom code can be disabled individually)
- "Grant consent by default" toggle — off by default (let DATA Reshape auto-detect your CMP / Google Consent Mode); on if you don't run a CMP and want events processed immediately

= API Events =
- Enable order webhook (server-to-server checkout_completed)
- Send order when status becomes … (default Processing; choose the status your payment flow reaches)
- Sends order_canceled automatically on Cancelled / Refunded orders
- Test mode (validate real payloads against the /test endpoint without delivering to destinations)
- Log webhook activity (adds a Logs tab showing WooCommerce's native drswc-webhook logs, scrolled to the latest)
- Requires your Tracking subdomain, Library ID, and Access token under Integration setup

== Frequently Asked Questions ==

= Does this plugin support GA4? =
Indirectly — events are pushed to DATA Reshape's `window.reshape` queue, and DATA Reshape routes them to GA4 and every other connected destination with the correct platform-specific event name and field mapping. You do not need to fire `gtag`, `fbq`, or `ttq` calls in parallel.

= Does it work without AJAX add-to-cart? =
Yes. It includes fallback mechanisms for redirect-based add-to-cart flows (native WooCommerce redirect to cart after adding a product).

= Does it support the block-based Cart/Checkout? =
The plugin's core events (Product Viewed, Add to Cart, Cart Viewed, Checkout Started, Checkout Completed) work on both legacy and block checkouts. The mid-funnel events (Billing Address Added, Shipping Detail Added, Payment Method Selected) currently fire on the legacy (shortcode-based) checkout only — block-based checkout support is planned for a later release.

= Does it support server-side event tracking? =
Yes — the "API Events" tab sends a server-to-server order webhook to DATA Reshape. It is not a blind CAPI mirror of the browser events; because the tracking library is first-party, browser events already get through reliably. The webhook instead covers what the browser can't: off-site payment gateways that confirm the order later (or where the shopper never returns to the thank-you page) and phone/admin orders with no browser session. DATA Reshape reconciles the webhook with the browser purchase by order number, so the two complement each other without double counting.

= Will this slow down my website? =
No. The plugin is designed with performance in mind and uses lightweight, conditional execution; if anything, your setup should see a boost in speed compared to classic integrations (Meta, TikTok and Google).

= Is deduplication handled? =
Deduplication is handled by DATA Reshape. The plugin focuses on exposing accurate and complete data for DATA Reshape to pickup and process onward.

== Screenshots ==

1. Initial dashboard with general settings (Integration setup tab)
2. Events configuration tab

== Changelog ==

= 1.0.5 =
- New: The API Events webhook reports the order creation source to `website` for storefront checkout, and distinct values for admin (`admin`), Point of Sale (`pos-rest-api`), and other API orders/methods.
- New: Logged-in customers now include their WordPress user role in `user.properties.role`. Guest and anonymous visitors are unaffected.

= 1.0.4 =
- Fix: Product, shipping, and coupon amounts now use one consistent tax basis matching, so stores that enter prices inclusive of tax no longer show non-sale products as discounted or under-report prices.

= 1.0.3 =
- Fix: Removed a PHP "Undefined array key" warning that could appear on the settings screen when rendering the API Events tab.

= 1.0.2 =
- Fix: Events could fail with "window.drswcPush is not a function" on sites that defer or delay JavaScript (Cloudflare Rocket Loader, WP Rocket / Perfmatters "delay JS", LiteSpeed, etc.). Events now queue until the script loads instead of erroring, so none are lost.

= 1.0.1 =
- Change: Failed, Cancelled, and Refunded are no longer selectable as the webhook trigger status — they aren't completion signals (Cancelled/Refunded already send the dedicated `order_canceled` event).

= 1.0.0 =
- New: Server-side order webhook (API Events tab). Sends a `checkout_completed` event server-to-server to DATA Reshape when an order reaches a configurable status (default Processing). It covers what the browser can't — off-site payment gateways that confirm minutes or hours later (or where the shopper never returns to the thank-you page) and phone/admin orders that never had a browser session. Uses the order number as the event ID so DATA Reshape deduplicates it against the browser purchase event; if one signal is missing the other fills in, with no double counting.
- New: `order_canceled` event sent on Cancelled / Refunded orders.
- New: The webhook reuses your existing Tracking subdomain and Library ID; the only new credential is an Access token (the former "API key" field, relabeled). An admin error notice appears if the webhook is enabled without an Access token.
- New: Relays DATA Reshape's first-party `drespa` cookie, captured on the order at checkout so it survives gateway callbacks and admin actions.
- New: The webhook sends the customer's IP (from the WooCommerce order, which resolves the real visitor IP behind proxies/CDNs such as Cloudflare) so events aren't attributed to the store server.
- New: Test mode routes webhooks to DATA Reshape's `/test` validation endpoint (nothing delivered to destinations) and surfaces the returned errors and warnings as an admin notice.
- New: Optional "Log webhook activity" toggle records each request and response in the WooCommerce logs (source `drswc-webhook`) and reveals a Logs tab in the settings for setup debugging.
- New: `drswc_webhook_payload` filter to customize the outgoing webhook envelope.
- New: Staging/local safety guard. If the site address no longer matches where DATA Reshape was set up (e.g. a database copied to a staging or local site), tracking is paused automatically and an admin bar offers to resume live tracking, keep it in test mode (events sent as "dev", not delivered), or dismiss — so a copy can't pollute your production data.
- New: A one-time welcome notice after activation prompts you to review every settings tab and configure it as needed.
- New: A "Realtime Analytics" tab that opens the DATA Reshape realtime dashboard in a new browser tab.
- Change: `stock_status` is now emitted as a string ("in stock" / "out of stock") instead of a boolean, matching DATA Reshape's stored format and avoiding a coercion warning.
- Internal: the admin CSS and the static frontend JS were moved out of PHP into real `assets/css` and `assets/js` files, enqueued with the plugin version for cache-busting. No functional change.
- Internal: the plugin was reorganized from one large file into a thin bootstrap plus focused trait files under `includes/`. It remains a single class/singleton; no functional change.
- Compatibility: tested up to WordPress 7.0 and WooCommerce 11.0.

= 0.9.1 =
- Fix: Add-to-cart now tracks reliably on stores where another plugin or theme intercepts the product-page button click before the standard handlers can run (volume-discount widgets, bundle plugins, one-click upsells, and similar).
- Fix: Add-to-cart no longer silently drops when `/wp-admin/admin-ajax.php` is unreachable (security-plugin allow-lists, expired nonces, ad-blocker rules, network drops). The product-page event payload now ships pre-built with the page, so the push happens synchronously.

= 0.9 =
- Fix: Add-to-cart now tracks reliably on themes that hijack the single-product form with their own AJAX (Woodmart, custom builders, etc.). A new product-page click handler on the standard `.single_add_to_cart_button` fires the event before the theme's submit logic runs, regardless of which AJAX library or endpoint the theme uses. Built-in 3-second JS dedup prevents double-fire when both this path and the legacy AJAX-listener path would trigger.
- Fix: Listing add-to-cart with WooCommerce's "Redirect to cart page after successful addition" option enabled — the `?add-to-cart=` link redirected to the cart page before any client-side hook could fire, so the event was lost. A new server-side `woocommerce_add_to_cart` action hook now stashes the pending event in session so it emits on the cart page after the redirect.
- Fix: Variable products on classic (non-AJAX) single-product pages now emit the chosen variation as `products[0].id` instead of the parent product id. The POST capture path was previously ignoring `variation_id`.
- Internal: the new server-side hook is intentionally gated on non-AJAX, non-REST, non-admin contexts so AJAX flows (already covered client-side) don't double-fire.

= 0.8 =
- Consent integration overhauled. The legacy "Google Consent Mode granted by default" toggle (emitted a `gtag('consent', 'update', ...)` block) and the per-event envelope `consent_default_grant` toggle have both been removed. A single new "Grant consent by default" toggle now fires DATA Reshape's native `consent_updated` push at session start — DATA Reshape detects most CMPs and Google Consent Mode v2 on its own, so this toggle defaults to OFF.
- Tax fields (`tax_included`, `tax_percent`) are now omitted entirely from product, coupon, and shipping payloads when WooCommerce tax is disabled (previously emitted as `tax_included: false`).
- Settings tabs renamed for clarity: "Browser events" → "Events", "Server-side events" → "API Events". The API Events tab is reserved for admin-recorded events (e.g. phone-call orders) and historical customer/order backfill — not a CAPI-style server-side mirror of browser events.
- Settings also reachable under Marketing → DATA Reshape (shortcut to the canonical WooCommerce → Settings → DATA Reshape page).
- Field labels simplified: "Server-side API endpoint" / "Server-side API key" → "API endpoint" / "API key".
- Internal: narrative inline comments moved to CLAUDE.md; no functional impact.

= 0.7 =
- Hard cutover from `window.dataLayer` to DATA Reshape's `window.reshape` API. Event names updated to the new spec (product_viewed, product_added_to_cart, cart_viewed, checkout_started, checkout_completed, etc.).
- Mid-funnel checkout events on legacy checkout: billing_address_added, shipping_detail_added, payment_method_selected.
- "Grant consent by default" and "Track checkout steps" toggles added.
- Identity emission tightened — `user` object sent only when logged in or in checkout with confirmed contact data.
- Variations carry parent_* fields; products emit categories[], stock status, type, created_at, image, gallery.
- Pricing decoupled from coupons — `price` / `price_base` are the buyer-visible regular / sale prices; coupons land in dedicated `coupons[]` arrays.
- New filters: `drswc_event_payload`, `drswc_product_payload`, `drswc_user_payload`, `drswc_consent_payload`.

= 0.6 =
- PII cache leak fix extended to cart/checkout pages (in addition to thankyou).
- HPOS and Cart/Checkout Blocks compatibility declared.

= 0.5 =
- Fixed PII leak on page-cached thankyou pages (LiteSpeed et al.) — identity now hydrated client-side from cookies.
- Removed browser-side SHA256 hashing — DATA Reshape hashes server-side.
- On-save tracking endpoint health check plus on-demand re-check button.
- wp.org update-available pill in the settings header.
- Loader URL tags the installed plugin version (`&wp=`).

= 0.4 =
- Fresh-install checkbox defaults flipped to off.
- Admin warning notice when the plugin is active but not configured.

= 0.3 =
- AJAX add-to-cart detection works with third-party plugins (QuadLayers etc.) and themes whose buttons don't expose `data-product_id`.
- Removed the in-page dataLayer debug overlay.

= 0.1 =
- Initial release.

== Upgrade Notice ==

= 1.0.5 =
Adds the order creation source (data_source) to the API Events webhook and the WordPress user role for logged-in customers. No action required.

= 1.0.4 =
Corrects VAT consistency across events. Recommended for stores that enter prices inclusive of tax.

= 1.0.3 =
Minor fix that clears a PHP warning on the settings screen. No action required.

= 1.0.2 =
Compatibility fix for sites that defer or delay JavaScript (Cloudflare Rocket Loader, WP Rocket, Perfmatters, LiteSpeed). No action required.

= 1.0.1 =
Tidies the webhook trigger-status dropdown (removes Failed, Cancelled, Refunded). No action required.

= 1.0.0 =
Adds the server-side order webhook under the API Events tab — reliable coverage for off-site payment gateways and phone/admin orders the browser can't capture. Off by default; enable it and add your Access token under Integration setup (the webhook reuses your Tracking subdomain and Library ID). Existing browser tracking is unchanged. Also adds a staging/local safety guard that auto-pauses tracking when a copied database is served from a different address, so test sites can't pollute your production data.

= 0.9.1 =
Fixes add-to-cart tracking on stores where another plugin or theme intercepts the product-page button click, and on stores where `/wp-admin/admin-ajax.php` is unreachable for any reason. No configuration required.

= 0.9 =
Fixes three add-to-cart tracking gaps: (a) themes that wrap the single-product submit in their own AJAX (Woodmart, custom builders); (b) listing add-to-cart with the "Redirect to cart page" WooCommerce option enabled; (c) variable products on classic single-product pages now emit the chosen variation instead of the parent. No configuration required.

= 0.8 =
**Have your technician roll this update out.** It changes the datalayer structure and the consent integration in ways that affect downstream destinations and any custom code reading from `window.reshape` / `window.drswcConsent`. Specifically: the old "Google Consent Mode granted by default" toggle no longer exists — sites that had it on must enable the new "Grant consent by default" toggle (Events tab) if they want events processed without waiting for a CMP signal; otherwise DATA Reshape's native CMP / Google Consent Mode v2 detection takes over. The `tax_included` / `tax_percent` fields are absent entirely (instead of `false`) when WooCommerce tax is disabled. After upgrade, verify in DATA Reshape that events still arrive as expected.

= 0.7 =
Breaking: migrates from `window.dataLayer` + `wc_*` event names to DATA Reshape's `window.reshape.push()` API with spec-defined names. Custom GTM tags reading the old `wc_*` events from this plugin's dataLayer will need updating. Verify in DATA Reshape that events are arriving after upgrade.

= 0.6 =
Extends the 0.5 PII cache-leak fix to cart/checkout pages and declares HPOS + Cart/Checkout Blocks compatibility.

= 0.5 =
Fixes a PII cache leak on page-cached thankyou pages (notably LiteSpeed). Identity is now hydrated client-side from cookies so cached HTML carries no PII.

= 0.4 =
Fresh-install checkbox defaults flipped to off (existing sites unaffected). Admin warning notice when the integration is active but not configured.

= 0.3 =
AJAX add-to-cart detection improved (QuadLayers et al.); in-page debug overlay removed.

= 0.1 =
Initial release.