PluginProbe
WPFunnels – Funnel Builder for WooCommerce with Checkout & One Click Upsell / 3.13.1
WPFunnels – Funnel Builder for WooCommerce with Checkout & One Click Upsell v3.13.1
3.13.1 3.13.0 3.12.13 3.12.12 3.12.11 3.12.10 3.12.9 3.12.8 3.12.7 3.12.6 3.12.5 3.12.4 3.12.3 3.12.1 3.12.2 3.12.0 3.11.1 3.11.0 3.10.9 3.10.8 3.10.7 3.10.6 2.8.16 2.8.17 2.8.18 All 259 releases
wpfunnels / includes / core / Reporting / StatHookHandler.php

StatHookHandler.php in WPFunnels – Funnel Builder for WooCommerce with Checkout & One Click Upsell 3.13.1, at includes/core/Reporting/StatHookHandler.php

317 lines 7.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace WPFunnels\Report;
4
5 use Automattic\WooCommerce\Utilities\OrderUtil;
6 use FKWCS\Gateway\Stripe\P24;
7 use WPFunnels\Wpfnl_functions;
8 use WPFunnels\Rest\Controllers\DashboardController;
9
10 class StatHookHandler
11 {
12
13 public function __construct()
14 {
15 add_action('wpfunnels/funnel_order_placed', array($this, 'update_stat_data_from_order'), 10, 3);
16 add_action('woocommerce_order_status_changed', array($this, 'change_order_status'), 10, 4);
17 add_action('template_redirect', array($this, 'track_funnel_checkout_visit'), 1);
18 add_action('wp_footer', array($this, 'track_native_checkout_visit'));
19
20 if (class_exists('\Automattic\WooCommerce\Utilities\OrderUtil') && function_exists('wc_get_container') && OrderUtil::custom_orders_table_usage_is_enabled()) {
21 add_action('woocommerce_delete_order', array($this, 'delete_stat_data'));
22 } else {
23 add_action('delete_post', array($this, 'delete_stat_data'));
24 }
25
26 add_action('woocommerce_order_fully_refunded', array($this, 'update_stat_table_for_full_refund'), 10, 1);
27 add_action('woocommerce_order_partially_refunded', array($this, 'update_stat_table_for_partial_refund'), 10, 2);
28 }
29
30
31 /**
32 * Update reporting data from order
33 *
34 * @param $order_id
35 * @param $funnel_id
36 * @param $checkout_id
37 */
38 public function update_stat_data_from_order($order_id, $funnel_id, $checkout_id)
39 {
40 global $wpdb;
41
42 $table = $wpdb->prefix . 'wpfnl_stats';
43 $order = wc_get_order($order_id);
44
45 if (!$order) {
46 return;
47 }
48
49 $status = $order->get_status();
50 $total = $order->get_total();
51 $customer_id = $order->get_customer_id();
52 $ob_revenue = $this->get_order_bump_revenue($order);
53 $current_date_time = current_time('mysql');
54 $current_date_time_gmt = current_time('mysql', 1);
55
56 $wpdb->insert(
57 $table,
58 array(
59 'order_id' => $order_id,
60 'funnel_id' => $funnel_id,
61 'customer_id' => $customer_id,
62 'total_sales' => $total,
63 'orderbump_sales' => $ob_revenue,
64 'status' => $status,
65 'date_created' => $current_date_time,
66 'date_created_gmt' => $current_date_time_gmt
67 )
68 );
69 }
70
71
72 /**
73 * Get order bump revenue from order
74 *
75 * @param $order
76 * @return int
77 *
78 * @since 3.1.7
79 */
80 public function get_order_bump_revenue($order)
81 {
82
83 $ob_products = $order->get_meta('_wpfunnels_order_bump_products');
84
85 if (empty($ob_products)) {
86 return 0;
87 }
88
89 $total = 0;
90
91 foreach ($order->get_items() as $item) {
92 $product_id = $item->get_product_id();
93
94 // If the product is a variation, get its variation ID
95 if ($item->get_variation_id()) {
96 $product_id = $item->get_variation_id();
97 }
98
99 if (in_array($product_id, $ob_products)) {
100 $total += $item->get_total();
101 }
102 }
103 return round($total, 2);
104 }
105
106
107 /**
108 * Update the order status if status changed.
109 *
110 * @param $order_id
111 * @param $old_status
112 * @param $new_status
113 * @param $order
114 *
115 * @since 3.2.0
116 */
117 public function change_order_status($order_id, $old_status, $new_status, $order)
118 {
119 global $wpdb;
120 $table = $wpdb->prefix . 'wpfnl_stats';
121
122 $offer_settings = Wpfnl_functions::get_offer_settings();
123 if ($offer_settings['offer_orders'] == 'main-order') {
124 $order_id = $order->get_id();
125 } else {
126 $parent_id = $order->get_meta('_wpfunnels_offer_parent_id');
127 $order_id = !empty($parent_id) ? $parent_id : $order->get_id();
128 }
129
130 if ('completed' === $new_status) {
131 $paid_date_time = current_time('mysql');
132 $wpdb->update(
133 $table,
134 array(
135 'status' => $new_status,
136 'paid_date' => $paid_date_time,
137 ),
138 array(
139 'order_id' => $order_id
140 )
141 );
142 DashboardController::delete_dashboard_cache();
143 } else {
144 $wpdb->update(
145 $table,
146 array(
147 'status' => $new_status,
148 ),
149 array(
150 'order_id' => $order_id
151 )
152 );
153 }
154
155 }
156
157
158 /**
159 * Delete stat if order is deleted
160 *
161 * @param $order_id
162 *
163 * @since 3.2.0
164 */
165 public function delete_stat_data($order_id)
166 {
167 if (empty($order_id) || absint(0 === $order_id)) {
168 return;
169 }
170
171 global $wpdb;
172 $table = $wpdb->prefix . 'wpfnl_stats';
173
174 if (0 < did_action('delete_post')) {
175 $get_post_type = get_post_type($order_id);
176 if ('shop_order' !== $get_post_type) {
177 return;
178 }
179 }
180 $wpdb->delete($table, ['order_id' => $order_id], ['%d']);
181 }
182
183
184 /**
185 * Update the stat table if fully refund is initiated
186 *
187 * @param $order_id
188 * @since 3.2.0
189 */
190 public function update_stat_table_for_full_refund($order_id)
191 {
192 global $wpdb;
193 $table = $wpdb->prefix . 'wpfnl_stats';
194 $wpdb->update(
195 $table,
196 array(
197 'total_sales' => 0,
198 'orderbump_sales' => 0,
199 'upsell_sales' => 0,
200 'downsell_sales' => 0,
201 ),
202 array(
203 'order_id' => $order_id
204 )
205 );
206 }
207
208
209
210 /**
211 * Update the stat table if partial refund is initiated
212 *
213 * @param $order_id
214 * @param $refund_id
215 *
216 * @since 3.2.0
217 */
218 public function update_stat_table_for_partial_refund($order_id, $refund_id)
219 {
220 global $wpdb;
221 $table = $wpdb->prefix . 'wpfnl_stats';
222 $order = wc_get_order($order_id);
223 $refund = wc_get_order($refund_id);
224 $refund_amount = 0;
225
226 if (!$order instanceof \WC_Order) {
227 return;
228 }
229
230 if (!$refund instanceof \WC_Order_Refund) {
231 return;
232 }
233
234 if (!Wpfnl_functions::check_if_funnel_order($order)) {
235 return;
236 }
237
238 $types = array(
239 'line_item',
240 'tax',
241 'shipping',
242 'fee',
243 'coupon',
244 );
245 if (0 < count($refund->get_items($types))) {
246 foreach ($refund->get_items($types) as $refund_item) {
247 $item_id = $refund_item->get_meta('_refunded_item_id', true);
248 if (empty($item_id)) {
249 continue;
250 }
251 $item = $order->get_item($item_id);
252 if (!$item instanceof \WC_Order_Item) {
253 continue;
254 }
255
256 $is_orderbump = $item->get_meta('_wpfunnels_order_bump');
257 $is_upsell = $item->get_meta('_wpfunnels_upsell');
258 $is_downsell = $item->get_meta('_wpfunnels_downsell');
259
260 if (('' === $is_orderbump) && ('' === $is_upsell) && ('' === $is_downsell)) {
261 $refund_amount += abs($refund_item->get_total());
262 }
263 }
264
265 if ($refund_amount > 0) {
266 $total = $wpdb->get_var("SELECT total_sales FROM " . $table . " WHERE order_id = " . $order_id);
267 $refund_amount = ($total <= $refund_amount) ? 0 : $total - $refund_amount;
268 $wpdb->update(
269 $table,
270 array(
271 'total_sales' => $refund_amount
272 ),
273 array(
274 'order_id' => $order_id
275 )
276 );
277 }
278 }
279 }
280
281
282 /**
283 * Track funnel checkout page visits.
284 * Runs at template_redirect priority 1, before any WC redirect hooks.
285 */
286 public function track_funnel_checkout_visit()
287 {
288 if ( is_admin() ) {
289 return;
290 }
291
292 if ( Wpfnl_functions::check_if_this_is_step_type( 'checkout' ) ) {
293 global $post;
294 $funnel_id = Wpfnl_functions::get_funnel_id_from_step( $post->ID );
295 CheckoutTracker::track_visit( 'funnel', $funnel_id );
296 CheckoutTracker::track_visit( 'store', 0 );
297 }
298 }
299
300 /**
301 * Track native WooCommerce checkout page visits.
302 * wp_footer fires only when a full page renders — WC's empty-cart redirect
303 * calls exit() before this point, so no cart check is needed here.
304 * Works for both classic shortcode and block-based checkout.
305 */
306 public function track_native_checkout_visit()
307 {
308 if ( ! function_exists( 'is_checkout' ) ) {
309 return;
310 }
311 if ( is_checkout() && ! is_wc_endpoint_url( 'order-received' ) && ! is_wc_endpoint_url( 'order-pay' ) ) {
312 CheckoutTracker::track_visit( 'store', 0 );
313 }
314 }
315
316 }
317