From 5fbcdb98f9c958edd4f6b997f25b1439a7439771 Mon Sep 17 00:00:00 2001 From: Brandon Estrella Date: Fri, 16 Oct 2026 19:40:32 -0700 Subject: [PATCH] Record WooCommerce purchase revenue; stop counting checkouts as revenue LinkForty sums a conversion's `value` as revenue. The purchase event now sends the order total as `value` (keeping `revenue` with the same total for existing filters), and begin_checkout sends its cart total as `cart_total` so a started checkout is not counted as revenue. The events docblock, README, readme.txt and the event contract in CONTRIBUTING.md now say `value` is revenue, and that the pixel drops nested objects rather than flattening them. --- CHANGELOG.md | 10 ++++++++++ CONTRIBUTING.md | 6 +++--- README.md | 4 ++-- includes/class-linkforty-events.php | 7 ++++--- includes/class-linkforty-woocommerce.php | 7 ++++++- readme.txt | 4 ++-- 6 files changed, 27 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5976b21..04ac206 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,16 @@ All notable changes to this plugin are documented here. The format follows ## [Unreleased] +### Fixed +- WooCommerce purchases record their revenue: the order total is sent as + `value`, the property LinkForty sums as revenue. `revenue` is still sent with + the same total. + +### Changed +- **Breaking:** `begin_checkout` sends the cart total as `cart_total` instead of + `value`, so a started checkout is not counted as revenue. Anything that reads + `begin_checkout`'s `value` should read `cart_total`. + ## [0.1.0] - 2026-10-11 Initial scaffold. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d915b2c..6f1a463 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -105,8 +105,8 @@ These rules exist because every store running the plugin reports with the same e - **A purchase is a confirmed order on the order-received page**, never a button click. Button clicks are intent. - **Each order is reported once.** The `_linkforty_purchase_tracked` order meta is the guard, and the ingestion endpoint does not deduplicate for us. - **Event names and properties are stable.** `purchase`, `begin_checkout`, and `add_to_cart` and their documented properties are an interface. Renaming or removing one is a breaking change that needs a major version and a changelog entry explaining the migration. Adding a property is fine. -- **Properties are flat.** Primitives and arrays of primitives only; the pixel flattens nested objects and caps the payload, so keep to what is documented in the README. -- **Monetary values go in `revenue`** for events that should count toward revenue, and in `value` for events that should not. +- **Properties are flat.** Primitives and arrays of primitives only; the pixel drops nested objects and caps the payload (30 properties), so keep to what is documented in the README. +- **`value` is revenue.** LinkForty sums the `value` of conversions as revenue, so only `purchase` sends one. Any other amount (a cart total, a product price) goes under its own key, such as `cart_total` or `price`. ## Testing @@ -118,7 +118,7 @@ Run through whichever rows your change can affect, with the browser network tab - [ ] Pixel tag present in `` on the home page, a product page, cart, and checkout, with the expected `data-*` attributes - [ ] A page view reaches the endpoint and returns `204` -- [ ] Place an order with the classic checkout. Exactly one `purchase` with the correct `order_id`, `revenue`, and `currency` +- [ ] Place an order with the classic checkout. Exactly one `purchase` with the correct `order_id`, `value`, and `currency` - [ ] Place an order with the block checkout. Same result - [ ] Refresh the order-received page. No second `purchase` - [ ] An order left `pending` (for example, a gateway that does not return) sends nothing; after it moves to `processing`, a visit to the order-received page sends one `purchase` diff --git a/README.md b/README.md index 5feda94..4118e15 100644 --- a/README.md +++ b/README.md @@ -26,8 +26,8 @@ Then mark `purchase` as a goal under Web analytics in LinkForty so it counts as | Event | When | Properties | |-------|------|------------| -| `purchase` | Order-received page, once per order, status processing / completed / on-hold | `order_id`, `revenue`, `currency`, `item_count`, `payment_method`, `coupon` | -| `begin_checkout` | Checkout page view with a non-empty cart | `value`, `currency`, `item_count` | +| `purchase` | Order-received page, once per order, status processing / completed / on-hold | `order_id`, `value` (order total, counted as revenue), `revenue` (same total), `currency`, `item_count`, `payment_method`, `coupon` | +| `begin_checkout` | Checkout page view with a non-empty cart | `cart_total`, `currency`, `item_count` | | `add_to_cart` | AJAX button, block cart, or product-page form submit | `product_id`, `quantity`, `sku`, plus `product_name`, `price`, `variation_id` on form submits | Events are handed to the browser pixel (`window.LinkForty.track`), never sent server to server. The pixel attaches the session's click id and UTM parameters, which is what attributes the event to a link. diff --git a/includes/class-linkforty-events.php b/includes/class-linkforty-events.php index cab4c6b..09e80ce 100644 --- a/includes/class-linkforty-events.php +++ b/includes/class-linkforty-events.php @@ -38,9 +38,10 @@ public static function init() { * Queues a conversion for the current page. * * @param string $name Event name, e.g. `purchase`. - * @param array $properties Flat properties. Use `revenue` - * for a monetary value so it rolls - * up in revenue reporting. + * @param array $properties Flat properties. `value` is the + * amount LinkForty sums as revenue, + * with `currency`; put any other + * amount under a different key. */ public static function track( $name, array $properties = array() ) { $name = trim( (string) $name ); diff --git a/includes/class-linkforty-woocommerce.php b/includes/class-linkforty-woocommerce.php index cf7592a..38f73b1 100644 --- a/includes/class-linkforty-woocommerce.php +++ b/includes/class-linkforty-woocommerce.php @@ -102,9 +102,12 @@ public static function track_purchase( $order_id ) { return; } + // `value` is the amount LinkForty sums as revenue. `revenue` carries the + // same total for filters written against the 0.1.0 payload. $coupons = $order->get_coupon_codes(); $properties = array( 'order_id' => (string) $order->get_id(), + 'value' => (float) $order->get_total(), 'revenue' => (float) $order->get_total(), 'currency' => $order->get_currency(), 'item_count' => (int) $order->get_item_count(), @@ -140,10 +143,12 @@ public static function track_begin_checkout() { return; } + // The cart total is not sent as `value`: LinkForty sums `value` as + // revenue, and a checkout that is started is not money received. LinkForty_Events::track( 'begin_checkout', array( - 'value' => (float) $cart->get_total( 'edit' ), + 'cart_total' => (float) $cart->get_total( 'edit' ), 'currency' => get_woocommerce_currency(), 'item_count' => (int) $cart->get_cart_contents_count(), ) diff --git a/readme.txt b/readme.txt index 429495b..b1a0845 100644 --- a/readme.txt +++ b/readme.txt @@ -21,8 +21,8 @@ LinkForty is a deep linking and attribution platform. This plugin adds the LinkF Events reported with WooCommerce enabled: -* `purchase` with `order_id`, `revenue`, `currency`, `item_count`, `payment_method`, `coupon` -* `begin_checkout` with `value`, `currency`, `item_count` +* `purchase` with `order_id`, `value` (the order total, counted as revenue), `revenue`, `currency`, `item_count`, `payment_method`, `coupon` +* `begin_checkout` with `cart_total`, `currency`, `item_count` * `add_to_cart` with `product_id`, `quantity`, `sku`, and on form submits `product_name`, `price`, `variation_id` Mark `purchase` as a goal under Web analytics in your LinkForty dashboard so it counts as a conversion.