Skip to content

Add NewCustomerResolverInterface extension point for new_customer field#37

Merged
MikeVerlinde merged 1 commit intomasterfrom
claude/fix-new-customer-calculation-3qyUo
Apr 24, 2026
Merged

Add NewCustomerResolverInterface extension point for new_customer field#37
MikeVerlinde merged 1 commit intomasterfrom
claude/fix-new-customer-calculation-3qyUo

Conversation

@koenvdwetering
Copy link
Copy Markdown

Summary

The new_customer field in the data layer is currently hardcoded to $order->getCustomerIsGuest() in three separate call sites:

  • DataLayer/Event/Purchase.php:84 — used by the MageWire/Hyva customer-data push via Observer/TriggerPurchaseDataLayerEvent
  • DataLayer/Tag/Order/UserData.php:57 — used by the shared Luma/Hyva success-page layout (view/frontend/layout/checkout_onepage_success.xml)
  • DataLayer/Event/PurchaseWebhookEvent.php:125 — used by the server-to-server webhook

Two problems with this:

  1. No upgrade-safe extension point. A merchant plugging into one location silently misses the other two. There is no ProcessorInterface hook for the webhook path, and afterGet plugins on Purchase don't cover the success-page tag.
  2. isGuest() is a poor proxy for "new customer". A returning customer can check out as a guest, and a new customer can register an account. More importantly, shops that convert guest orders into customer accounts on sales_order_place_after observe isGuest() === false by the time the value is read, so Google Ads' new-customer bid-modifier never receives a signal.

This PR extracts the check into NewCustomerResolverInterface (isNewCustomer(OrderInterface): bool) with a default IsGuestResolver implementation that preserves existing behavior. All three call sites now delegate to the resolver.

For merchants

Override the default by adding a preference in your own module's di.xml:

<preference for="Tagging\GTM\Api\NewCustomerResolverInterface"
            type="Vendor\Module\Model\PriorOrderCountResolver"/>

Backwards compatibility

No behavior change for existing installations — the default resolver returns (bool)$order->getCustomerIsGuest(), matching the previous three hardcoded expressions.

Test plan

  • bin/magento setup:di:compile succeeds (new interface + preference resolve)
  • Existing TriggerPurchaseDataLayerEventTest integration test still passes
  • Guest checkout on success page emits new_customer: "true" in dataLayer (default behavior preserved)
  • Registered customer checkout emits new_customer: "false" (default behavior preserved)
  • Webhook payload contains matching new_customer value
  • A custom preference (e.g. always-true resolver) takes effect across all three emit points

https://claude.ai/code/session_01KrUuLFtrNMyY2ZuwrvH8db


Generated by Claude Code

The `new_customer` value is emitted from three separate call sites
(Purchase event, UserData order tag, and PurchaseWebhookEvent), each
hardcoding `$order->getCustomerIsGuest()` as the heuristic. That leaves
no single, upgrade-safe extension point for merchants who want a
different definition (e.g. based on prior order count), and breaks for
shops that convert guest orders into customer accounts on
`sales_order_place_after` — isGuest() is false by the time the value is
read.

Extract the check into NewCustomerResolverInterface with a default
IsGuestResolver implementation that preserves existing behavior.
Merchants can now override the heuristic with a single DI preference.

https://claude.ai/code/session_01KrUuLFtrNMyY2ZuwrvH8db
@MikeVerlinde MikeVerlinde merged commit 6b6397f into master Apr 24, 2026
1 check passed
@MikeVerlinde MikeVerlinde deleted the claude/fix-new-customer-calculation-3qyUo branch April 24, 2026 09:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants