Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
6 changes: 3 additions & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -118,7 +118,7 @@ Run through whichever rows your change can affect, with the browser network tab

- [ ] Pixel tag present in `<head>` 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`
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
7 changes: 4 additions & 3 deletions includes/class-linkforty-events.php
Original file line number Diff line number Diff line change
Expand Up @@ -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<string, mixed> $properties Flat properties. Use `revenue`
* for a monetary value so it rolls
* up in revenue reporting.
* @param array<string, mixed> $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 );
Expand Down
7 changes: 6 additions & 1 deletion includes/class-linkforty-woocommerce.php
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Expand Down Expand Up @@ -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(),
)
Expand Down
4 changes: 2 additions & 2 deletions readme.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
Loading