PluginProbe
Plausible Analytics / trunk
Plausible Analytics vtrunk
2.6.1 2.6.0 trunk 1.0.0 1.0.1 1.1.0 1.2.0 1.2.1 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 2.0.0 2.0.1 2.0.2 2.0.3 2.0.4 All 52 releases
plausible-analytics / src / Integrations / EDD.php

EDD.php in Plausible Analytics trunk, at src/Integrations/EDD.php

227 lines 6.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Plausible Analytics | Integrations | EDD.
4 *
5 * @since 2.1.0
6 * @package WordPress
7 * @subpackage Plausible Analytics
8 */
9
10 namespace Plausible\Analytics\WP\Integrations;
11
12 use Plausible\Analytics\WP\EnhancedMeasurements;
13 use Plausible\Analytics\WP\Integrations;
14 use Plausible\Analytics\WP\Proxy;
15
16 /**
17 * @codeCoverageIgnore Because all we'd be testing is the (external) API.
18 */
19 class EDD {
20 public $event_goals = [];
21
22 /**
23 * Build class.
24 *
25 * @param $init
26 */
27 public function __construct( $init = true ) {
28 $uri = defined( 'EDD_SLUG' ) ? EDD_SLUG : 'downloads';
29
30 if ( is_multisite() ) {
31 $uri = get_blog_details()->path . $uri;
32 } else {
33 $uri = '/' . $uri;
34 }
35
36 $this->event_goals = [
37 // translators: %s: Product page URI pattern.
38 'view-product' => sprintf( __( 'Visit %s*', 'plausible-analytics' ), $uri ),
39 'add-to-cart' => __( 'EDD Add to Cart', 'plausible-analytics' ),
40 'remove-from-cart' => __( 'EDD Remove from Cart', 'plausible-analytics' ),
41 'checkout' => __( 'EDD Start Checkout', 'plausible-analytics' ),
42 'purchase' => __( 'EDD Complete Purchase', 'plausible-analytics' ),
43 ];
44
45 $this->init( $init );
46 }
47
48 /**
49 * Action & filter hooks.
50 *
51 * @param $init
52 *
53 * @return void
54 */
55 private function init( $init ) {
56 if ( ! $init ) {
57 return;
58 }
59
60 add_action( 'edd_post_add_to_cart', [ $this, 'track_add_to_cart' ], 10, 3 );
61 add_action( 'edd_pre_remove_from_cart', [ $this, 'track_remove_cart_item' ], 10 );
62 add_action( 'edd_before_purchase_form', [ $this, 'track_entered_checkout' ] );
63 add_action( 'wp_head', [ $this, 'track_purchase' ] );
64 }
65
66 /**
67 * Tracks the "add to cart" event with relevant product and cart data.
68 *
69 * @param int $download_id The ID of the product being added to the cart.
70 * @param array $options Optional data associated with the product being added.
71 * @param array $items The current items in the cart.
72 *
73 * @return void
74 *
75 * @codeCoverageIgnore Because we can't test XHR requests here.
76 */
77 public function track_add_to_cart( $download_id, $options, $items ) {
78 $download = new \EDD_Download( $download_id );
79
80 if ( $download->ID === 0 ) {
81 return;
82 }
83
84 $quantity = array_filter(
85 $items,
86 function ( $item ) use ( $download_id ) {
87 return $item['id'] === $download_id;
88 }
89 );
90 $quantity = reset( $quantity )['quantity'] ?? 1;
91
92 $props = apply_filters(
93 'plausible_analytics_edd_add_to_cart_custom_properties',
94 [
95 'product_name' => edd_get_download_name( $download_id ),
96 'product_id' => $download_id,
97 'quantity' => $quantity,
98 'price' => edd_get_download_price( $download_id ),
99 'tax_class' => edd_get_cart_tax_rate(),
100 'cart_total_items' => edd_get_cart_quantity(),
101 'cart_total' => edd_get_cart_total(),
102 ]
103 );
104
105 $proxy = new Proxy( false );
106
107 $proxy->do_request( $this->event_goals['add-to-cart'], null, null, $props );
108 }
109
110 /**
111 * Tracks the removal of an item from the cart, updates cart contents and triggers an event to log this action.
112 *
113 * @param string|int $key The key of the item in the cart to be removed.
114 *
115 * @return void
116 *
117 * @codeCoverageIgnore Because we can't test XHR requests here.
118 */
119 public function track_remove_cart_item( $key ) {
120 $cart_contents = edd_get_cart_contents();
121 $item_removed_from_cart = $cart_contents[ $key ] ?? [];
122 $product = null;
123
124 if ( empty( $item_removed_from_cart ) ) {
125 return;
126 }
127
128 unset( $cart_contents[ $key ] );
129
130 if ( isset( $item_removed_from_cart['id'] ) ) {
131 $product = new \EDD_Download( $item_removed_from_cart['id'] );
132 }
133
134 if ( ! $product ) {
135 return;
136 }
137
138 $total_removed_from_cart = edd_get_cart_total() - ( $product->get_price() * $item_removed_from_cart['quantity'] );
139
140 $props = apply_filters(
141 'plausible_analytics_edd_remove_cart_item_custom_properties',
142 [
143 'product_name' => $product->get_name(),
144 'product_id' => $item_removed_from_cart['id'],
145 'quantity' => $item_removed_from_cart['quantity'],
146 'cart_total_items' => count( $cart_contents ),
147 'cart_total' => $total_removed_from_cart,
148 ]
149 );
150
151 $proxy = new Proxy( false );
152
153 $proxy->do_request( $this->event_goals['remove-from-cart'], null, null, $props );
154 }
155
156 /**
157 * Tracks the "entered checkout" event with relevant cart data.
158 *
159 * @return void
160 *
161 * @codeCoverageIgnore Because we can't test XHR requests here.
162 */
163 public function track_entered_checkout() {
164 // Just to make sure we're where we're supposed to be.
165 if ( ! edd_is_checkout() ) {
166 return;
167 }
168
169 $props = apply_filters(
170 'plausible_analytics_edd_entered_checkout_custom_properties',
171 [
172 // @todo Add cart contents
173 'subtotal' => edd_get_cart_subtotal(),
174 'tax' => edd_get_cart_tax(),
175 'total' => edd_get_cart_total(),
176 ]
177 );
178
179 $proxy = new Proxy( false );
180
181 $proxy->do_request( $this->event_goals['checkout'], null, null, $props );
182 }
183
184 /**
185 * Tracks the "purchase" event with relevant payment data.
186 *
187 * We choose to render a JS script, instead of hooking into an action, because user-agent information
188 * gets lost when the user is first redirected to a Payment Provider.
189 *
190 * @return void
191 */
192 public function track_purchase() {
193 if ( ! edd_is_success_page() ) {
194 return; // @codeCoverageIgnore
195 }
196
197 $session = edd_get_purchase_session();
198 $order = null;
199
200 if ( ! empty( $session['purchase_key'] ) ) {
201 $order = edd_get_order_by( 'payment_key', $session['purchase_key'] );
202 }
203
204 // Don't track on page reload.
205 if ( ! $order || edd_get_order_meta( $order->id, Integrations::PURCHASE_TRACKED_META_KEY, true ) ) {
206 return;
207 }
208
209 $props = wp_json_encode(
210 apply_filters(
211 'plausible_analytics_edd_purchase_custom_properties',
212 [
213 EnhancedMeasurements::ECOMMERCE_REVENUE => [
214 'amount' => $order->total,
215 'currency' => $order->currency,
216 ],
217 ]
218 )
219 );
220 $label = $this->event_goals['purchase'];
221
222 echo sprintf( Integrations::SCRIPT_WRAPPER, "window.plausible( '$label', $props )" );
223
224 edd_add_order_meta( $order->id, Integrations::PURCHASE_TRACKED_META_KEY, true );
225 }
226 }
227