PluginProbe
Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) / 1.8.11.1
Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) v1.8.11.1
1.8.13.1 1.8.13 1.8.12.3 1.8.12.2 1.8.12.1 1.8.12 1.8.11.3 1.8.11.2 1.8.11.1 1.8.11 1.6.6 1.6.60 1.6.7 1.6.8 1.6.9 1.7.0 1.7.0.1 1.7.0.11 1.7.0.12 1.7.0.14 1.7.0.2 1.7.0.3 1.7.0.5 1.7.0.6 1.7.0.7 All 212 releases
charitable / includes / admin / tracking / class-charitable-tracking.php

class-charitable-tracking.php in Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) 1.8.11.1, at includes/admin/tracking/class-charitable-tracking.php

933 lines 28.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Tracking functions for reporting plugin usage (optin) and anonymous tracking (optin) to the Charitable site for users
4 *
5 * @access public
6 * @package Charitable
7 * @subpackage Admin
8 * @copyright Copyright (c) 2024, David Bisset
9 * @since 1.8.4
10 * @version 1.8.4.5
11 */
12
13 // Exit if accessed directly.
14 if ( ! defined( 'ABSPATH' ) ) {
15 exit;
16 }
17
18 if ( ! class_exists( 'Charitable_Tracking' ) ) {
19 /**
20 * Usage tracking
21 */
22 class Charitable_Tracking {
23
24 /**
25 * The single instance of this class.
26 *
27 * @var Charitable_Tracking|null
28 */
29 private static $instance = null;
30
31 /**
32 * Class init function.
33 */
34 public function __construct() {
35 }
36
37 /**
38 * Starts the process of sending in the optin usage checking.
39 *
40 * @since 1.8.4.2
41 *
42 * @param boolean $override Override usage_optin_allowed.
43 * @param boolean $ignore_last_checkin Ignore last checkin flag.
44 *
45 * @return void
46 */
47 public function send_checkins( $override = false, $ignore_last_checkin = false ) {
48 $this->send_optin_usage_checkin( $override, $ignore_last_checkin );
49 $this->send_tracking_checkin( $override, $ignore_last_checkin );
50 }
51
52 /**
53 * Manually sends tracking data if optin is enabled. Testing purposes only.
54 *
55 * @since 1.8.4
56 *
57 * @return void
58 */
59 public function test_checkin() {
60 if ( is_admin() && current_user_can( 'manage_options' ) && defined( 'CHARITABLE_DEBUG_USAGE' ) && CHARITABLE_DEBUG_USAGE ) { // phpcs:ignore
61 // detect the query string in the admin url.
62 $send_checkin = isset( $_GET['charitable_send_checkin'] ) ? sanitize_text_field( wp_unslash( $_GET['charitable_send_checkin'] ) ) : false; // phpcs:ignore
63 if ( charitable_is_debug() ) {
64 error_log( 'charitable test checkin triggered' ); // phpcs:ignore
65 }
66 if ( 'usage' === $send_checkin ) {
67 if ( charitable_is_debug() ) {
68 error_log( 'charitable test checkin was run for usage' ); // phpcs:ignore
69 }
70 $this->send_optin_usage_checkin( true, true );
71 } elseif ( 'tracking' === $send_checkin ) {
72 if ( charitable_is_debug() ) {
73 error_log( 'charitable test checkin was run for tracking' ); // phpcs:ignore
74 }
75 $this->send_tracking_checkin( true, true );
76 } elseif ( 'both' === $send_checkin ) {
77 if ( charitable_is_debug() ) {
78 error_log( 'charitable test checkin was run for both' ); // phpcs:ignore
79 }
80 $this->send_optin_usage_checkin( true, true );
81 $this->send_tracking_checkin( true, true );
82 }
83 }
84 }
85
86 /**
87 * Fetch tracking data.
88 *
89 * @since 1.8.4
90 * @version 1.8.4.5
91 *
92 * @return array $data Tracked data.
93 */
94 private function get_optin_data() {
95
96 global $wpdb;
97
98 $data = array();
99
100 // get charitable settings.
101 $charitable_settings = get_option( 'charitable_settings' );
102
103 // Retrieve current theme info.
104 $theme_data = wp_get_theme();
105
106 $count_b = 1;
107 if ( is_multisite() ) {
108 if ( function_exists( 'get_blog_count' ) ) {
109 $count_b = get_blog_count();
110 } else {
111 $count_b = '0';
112 }
113 }
114
115 $charitable_object = charitable();
116
117 // get license info.
118 $licenses = ! empty( $charitable_settings['licenses'] ) ? $charitable_settings['licenses'] : array();
119 $country = ! empty( $charitable_settings['country'] ) ? $charitable_settings['country'] : '';
120 $currency = ! empty( $charitable_settings['currency'] ) ? $charitable_settings['currency'] : '';
121 $default_gateway = ! empty( $charitable_settings['default_gateway'] ) ? $charitable_settings['default_gateway'] : '';
122
123 $data['php_version'] = phpversion();
124 $data['wpchar_version'] = $charitable_object !== null ? charitable()->get_version() : '';
125 $data['wp_version'] = get_bloginfo( 'version' );
126 $data['servertype'] = isset( $_SERVER['SERVER_SOFTWARE'] ) ? sanitize_text_field( wp_unslash( $_SERVER['SERVER_SOFTWARE'] ) ) : '';
127 $data['upgraded_from'] = get_option( 'charitable_upgraded_from', '' );
128 $data['activated'] = get_option( 'charitable_activated', '' );
129 $data['activated_datetime'] = get_option( 'wpcharitable_activated_datetime', '' );
130 $data['first_campaign'] = get_option( 'charitable_first_campaign', '' );
131 $data['first_donation'] = get_option( 'charitable_first_donation', '' );
132 $data['multisite'] = is_multisite();
133 $data['url'] = home_url();
134 $data['themename'] = $theme_data->Name; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
135 $data['themeversion'] = $theme_data->Version; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
136 $data['email'] = get_bloginfo( 'admin_email' );
137 $data['licenses'] = $licenses;
138 $data['country'] = $country;
139 $data['currency'] = $currency;
140 $data['default_gateway'] = $default_gateway;
141 $data['pro'] = function_exists( 'charitable_pro' ) ? charitable_is_pro() : false;
142 $data['sites'] = $count_b;
143 $data['usagetracking'] = get_option( 'charitable_usage_tracking_config', false );
144 $data['usercount'] = function_exists( 'count_users' ) ? count_users()['total_users'] : '0';
145 $data['timezoneoffset'] = gmdate( 'P' );
146 $data['wc_active'] = $this->check_if_wc_active();
147 $data['usages'] = array(
148 'blocks' => $this->block_count_summation(),
149 'wp_pages' => $this->get_wp_pages(),
150 'wp_posts' => $this->get_wp_posts(),
151 );
152
153 // Add recommendation tracking data
154 $data['recommended_plugins_viewed'] = get_option( 'charitable_recommended_plugins_viewed', array() );
155 $data['recommended_plugins_clicked'] = get_option( 'charitable_recommended_plugins_clicked', array() );
156 $data['recommended_plugins_installed'] = get_option( 'charitable_recommended_plugins_installed', array() );
157 $data['recommended_plugins_activated'] = get_option( 'charitable_recommended_plugins_activated', array() );
158 $data['dashboard_enhance_section_views'] = get_option( 'charitable_dashboard_enhance_views', 0 );
159
160 // Retrieve current plugin information.
161 if ( ! function_exists( 'get_plugins' ) ) {
162 include ABSPATH . '/wp-admin/includes/plugin.php';
163 }
164
165 $plugins = array_keys( get_plugins() );
166 $active_plugins = get_option( 'active_plugins', array() );
167
168 foreach ( $plugins as $key => $plugin ) {
169 if ( in_array( $plugin, $active_plugins, true ) ) {
170 // Remove active plugins from list so we can show active and inactive separately.
171 unset( $plugins[ $key ] );
172 }
173 }
174
175 $data['active_plugins'] = $active_plugins;
176 $data['inactive_plugins'] = $plugins;
177 $data['locale'] = get_locale();
178
179 return $data;
180 }
181
182
183 /**
184 * Fetch tracking data.
185 *
186 * @since 1.8.4
187 *
188 * @return array $data Tracked data.
189 */
190 private function get_tracking_data() {
191
192 global $wpdb;
193
194 $data = array();
195
196 $data['id'] = $this->get_site_aid();
197
198 // get the total number of campaigns.
199 $data['campaign_counts'] = (array) wp_count_posts( 'campaign' );
200
201 // campaign data.
202 $data['campaign_data'] = (array) $this->get_charitable_data();
203
204 // donation data.
205 $data['donation_data'] = $this->get_donation_data();
206 $data['recurring_donation_data'] = $this->get_recurring_donation_data();
207
208 return $data;
209 }
210
211 /**
212 * Get Charitable data.
213 *
214 * @return array $data Charitable data.
215 */
216 public function get_charitable_data() {
217
218 global $wpdb;
219
220 $sql = "SELECT
221 SUM(subquery.total_amount) AS grand_total_amount,
222 AVG(subquery.total_amount) AS grand_average_amount,
223 SUM(subquery.total_count_donations) AS grand_total_count_donations
224 FROM (
225 SELECT
226 SUM(ccd.amount) AS total_amount,
227 COUNT(ccd.donation_id) AS total_count_donations,
228 cd.donor_id
229 FROM {$wpdb->prefix}charitable_donors cd
230 JOIN {$wpdb->prefix}charitable_campaign_donations ccd ON cd.donor_id = ccd.donor_id
231 GROUP BY cd.donor_id
232 ) AS subquery;
233 ";
234
235 $results = $wpdb->get_results( $sql, ARRAY_A ); // phpcs:ignore
236
237 $data = [];
238
239 if ( ! empty( $results ) ) {
240 // Ensure each amount is converted to a string before sanitization.
241 $data['total'] = 0 !== $results[0]['grand_total_amount']
242 ? charitable_sanitize_amount( (string) ( $results[0]['grand_total_amount'] ), true )
243 : 0;
244
245 $data['average'] = 0 !== $results[0]['grand_average_amount']
246 ? charitable_sanitize_amount( (string) ( $results[0]['grand_average_amount'] ), true )
247 : 0;
248 $data['donor_count'] = 0 !== $results[0]['grand_total_count_donations'] ? intval( $results[0]['grand_total_count_donations'] ) : 0;
249 }
250
251 if ( ! empty( $data ) ) {
252 return $data;
253 }
254 }
255
256 /**
257 * Get donation related data.
258 *
259 * @since 1.8.4
260 *
261 * @return array $data Donation data.
262 */
263 public function get_donation_data() {
264
265 global $wpdb;
266
267 $defaults = array(
268 'start_date' => false,
269 'end_date' => false,
270 'post_status' => 'charitable-completed',
271 'campaign_id' => false,
272 'category_id' => false,
273 );
274
275 // Extract individual variables from defaults array.
276 $start_date = $defaults['start_date'];
277 $end_date = $defaults['end_date'];
278 $post_status = $defaults['post_status'];
279 $campaign_id = $defaults['campaign_id'];
280 $category_id = $defaults['category_id'];
281
282 $where_sql = array();
283 $where_sql[] = 'WHERE 1=1';
284 $where_sql[] = 'p.post_type = "%s"';
285 $where_sql[] = 'p.post_status = "' . $post_status . '"';
286 $where_sql[] = 'pm1.meta_key = "donation_gateway"';
287
288 // remove all empty values from the array.
289 $where_sql = array_filter( $where_sql );
290 $where_args = implode( ' AND ', $where_sql );
291
292 $left_join = array();
293 $left_join[] = $wpdb->prefix . 'charitable_campaign_donations cd ON p.ID = cd.donation_id';
294 $left_join[] = $wpdb->prefix . 'charitable_donors cdonors ON cd.donor_id = cdonors.donor_id';
295 $left_join[] = $wpdb->prefix . 'postmeta pm1 ON p.ID = pm1.post_id';
296
297 // remove all empty values from the array.
298 $left_join = array_filter( $left_join );
299 $left_join_args = 'LEFT JOIN ' . implode( ' LEFT JOIN ', $left_join );
300
301 $sql = "SELECT SUM(cd.amount) AS total_amount,
302 cd.donation_id AS donation_id,
303 cd.campaign_id AS campaign_id,
304 cd.donor_id AS donor_id,
305 cd.amount AS amount,
306 pm1.meta_value AS payment_gateway,
307 p.post_date AS post_date,
308 p.post_date_gmt AS post_date_gmt,
309 p.post_status AS donation_status,
310 p.post_type AS donation_type,
311 p.post_parent AS donation_parent_id
312 FROM $wpdb->posts p
313 " . $left_join_args . '
314 ' . $where_args . '
315 GROUP BY p.ID';
316
317 $donations = $wpdb->get_results( // phpcs:ignore
318 $wpdb->prepare(
319 $sql, // phpcs:ignore
320 'donation'
321 )
322 );
323
324 // get total all time donations.
325 $total_donations = 0;
326 foreach ( $donations as $donation ) {
327 $total_donations += $donation->total_amount;
328 }
329
330 // get total donations in the past 7 days.
331 $donations_7_days = 0;
332 foreach ( $donations as $donation ) {
333 if ( strtotime( $donation->post_date ) > strtotime( '-7 days' ) ) {
334 $donations_7_days += $donation->total_amount;
335 }
336 }
337
338 // get total donations from the last 30 days.
339 $donations_30_days = 0;
340 foreach ( $donations as $donation ) {
341 if ( strtotime( $donation->post_date ) > strtotime( '-30 days' ) ) {
342 $donations_30_days += $donation->total_amount;
343 }
344 }
345
346 // get donations by payment gateway.
347 $donations_payment_gateway = array();
348 foreach ( $donations as $donation ) {
349 if ( ! isset( $donations[ $donation->payment_gateway ] ) ) {
350 $donations_payment_gateway[ $donation->payment_gateway ] = 0;
351 }
352 $donations_payment_gateway[ $donation->payment_gateway ] += $donation->total_amount;
353 }
354
355 return array(
356 'total_donations' => $total_donations,
357 'donations_7_days' => $donations_7_days,
358 'donations_30_days' => $donations_30_days,
359 'donations_payment_gateway' => $donations_payment_gateway,
360 );
361 }
362
363 /**
364 * Get recurring donation related data.
365 *
366 * @since 1.8.4
367 *
368 * @return array $data Recurring donation data.
369 */
370 public function get_recurring_donation_data() {
371
372 global $wpdb;
373
374 // if the recurring donations plugin is not active, return an empty array.
375 if ( ! class_exists( 'Charitable_Recurring' ) ) {
376 return array();
377 }
378
379 $where_sql = array();
380 $where_sql[] = 'WHERE 1=1';
381 $where_sql[] = 'p.post_type = "%s"';
382 $where_sql[] = 'p.post_status = "charitable-active"';
383 $where_sql[] = 'pm1.meta_key = "donation_gateway"';
384 $where_sql[] = 'pm2.meta_key = "donation_period"';
385 $where_sql[] = 'pm3.meta_key = "_first_donation"';
386 $where_sql[] = 'pm4.meta_key = "_expiration_date"';
387
388 // remove all empty values from the array.
389 $where_sql = array_filter( $where_sql );
390 $where_args = implode( ' AND ', $where_sql );
391
392 $left_join = array();
393 $left_join[] = $wpdb->prefix . 'postmeta pm1 ON p.ID = pm1.post_id';
394 $left_join[] = $wpdb->prefix . 'postmeta pm2 ON p.ID = pm2.post_id';
395 $left_join[] = $wpdb->prefix . 'postmeta pm3 ON p.ID = pm3.post_id';
396 $left_join[] = $wpdb->prefix . 'postmeta pm4 ON p.ID = pm4.post_id';
397 $left_join = array_filter( $left_join );
398 $left_join_args = 'LEFT JOIN ' . implode( ' LEFT JOIN ', $left_join );
399
400 $sql = "SELECT SUM(pm4.meta_value) AS total_recurring_amount,
401 pm1.meta_value AS payment_gateway,
402 pm2.meta_value AS donation_period,
403 pm3.meta_value AS first_donation,
404 pm4.meta_value AS expiration_date,
405 p.post_date AS post_date,
406 p.post_date_gmt AS post_date_gmt,
407 p.post_status AS donation_status,
408 p.post_parent AS donation_parent_id
409 FROM $wpdb->posts p
410 " . $left_join_args . '
411 ' . $where_args . '
412 GROUP BY p.ID';
413
414 $recurring_donations = $wpdb->get_results( // phpcs:ignore
415 $wpdb->prepare(
416 $sql, // phpcs:ignore
417 'recurring_donation'
418 )
419 );
420
421 $total_recurring_amount = $recurring_donations ? array_sum( wp_list_pluck( $recurring_donations, 'first_donation' ) ) : 0;
422
423 // get recurring donations by payment gateway.
424 $recurring_donations_payment_gateway = array();
425 foreach ( $recurring_donations as $donation ) {
426 if ( ! isset( $recurring_donations_payment_gateway[ $donation->payment_gateway ] ) ) {
427 $recurring_donations_payment_gateway[ $donation->payment_gateway ] = 0;
428 }
429 $recurring_donations_payment_gateway[ $donation->payment_gateway ] += $donation->first_donation;
430 }
431
432 // get recurring donations by period.
433 $recurring_donations_period = array();
434 foreach ( $recurring_donations as $donation ) {
435 if ( ! isset( $recurring_donations_period[ $donation->donation_period ] ) ) {
436 $recurring_donations_period[ $donation->donation_period ] = 0;
437 }
438 $recurring_donations_period[ $donation->donation_period ] += $donation->first_donation;
439 }
440
441 // get total recurring donations in the past 7 days.
442 $recurring_donations_7_days = 0;
443 foreach ( $recurring_donations as $donation ) {
444 if ( strtotime( $donation->post_date ) > strtotime( '-7 days' ) ) {
445 $recurring_donations_7_days += $donation->first_donation;
446 }
447 }
448
449 // get total recurring donations from the last 30 days.
450 $recurring_donations_30_days = 0;
451 foreach ( $recurring_donations as $donation ) {
452 if ( strtotime( $donation->post_date ) > strtotime( '-30 days' ) ) {
453 $recurring_donations_30_days += $donation->first_donation;
454 }
455 }
456
457 return array(
458 'total_recurring_amount' => $total_recurring_amount,
459 'recurring_donations_payment_gateway' => $recurring_donations_payment_gateway,
460 'recurring_donations_period' => $recurring_donations_period,
461 'recurring_donations_7_days' => $recurring_donations_7_days,
462 'recurring_donations_30_days' => $recurring_donations_30_days,
463 );
464 }
465
466 /**
467 * Send optin usage data.
468 *
469 * @since 1.8.4
470 *
471 * @param boolean $override Override usage_optin_allowed.
472 * @param boolean $ignore_last_checkin Ignore last checkin flag.
473 * @return boolean
474 */
475 public function send_optin_usage_checkin( $override = false, $ignore_last_checkin = false ) {
476
477 if ( defined( 'CHARITABLE_DEBUG_USAGE' ) && CHARITABLE_DEBUG_USAGE ) { // phpcs:disable
478 // phpcs:disable
479 if ( charitable_is_debug() ) {
480 error_log('send_optin_usage_checkin');
481 }
482 // phpcs:enable
483 }
484
485 if ( ! $this->usage_optin_allowed() && ! $override ) {
486 if ( defined( 'CHARITABLE_DEBUG_USAGE' ) && CHARITABLE_DEBUG_USAGE ) { // phpcs:disable
487 // phpcs:disable
488 if ( charitable_is_debug() ) {
489 error_log('charitable usage tracking not allowed');
490 }
491 // phpcs:enable
492 }
493 return false;
494 }
495
496 // Send a maximum of once per week.
497 $last_send = get_option( 'charitable_usage_tracking_last_checkin' );
498 if ( is_numeric( $last_send ) && $last_send > strtotime( '-1 week' ) && ! $ignore_last_checkin ) {
499 if ( defined( 'CHARITABLE_DEBUG_USAGE' ) && CHARITABLE_DEBUG_USAGE ) { // phpcs:disable
500 // phpcs:disable
501 if ( charitable_is_debug() ) {
502 error_log('charitable usage tracking not allowed because of last checkin');
503 }
504 // phpcs:enable
505 }
506 return false;
507 }
508
509 $charitable_object = charitable();
510 $charitable_version = $charitable_object !== null ? charitable()->get_version() : '';
511
512 $request = wp_remote_post(
513 'https://usage.wpcharitable.com/capture',
514 array(
515 'method' => 'POST',
516 'timeout' => 15,
517 'redirection' => 5,
518 'httpversion' => '1.1',
519 'blocking' => true,
520 'sslverify' => false,
521 'body' => $this->get_optin_data(),
522 'user-agent' => 'CH/' . $charitable_version . '; ' . get_bloginfo( 'url' ),
523 )
524 );
525
526 if ( defined( 'CHARITABLE_DEBUG_USAGE' ) && CHARITABLE_DEBUG_USAGE ) { // phpcs:disable
527 // phpcs:disable
528 if ( charitable_is_debug() ) {
529 error_log( 'send_optin_usage_checkin' );
530 error_log( print_r( $request, true ) );
531 error_log( print_r( $this->get_optin_data(), true ) );
532 }
533 // phpcs:enable
534 }
535
536 if ( ! is_wp_error( $request ) ) {
537 // If we have completed successfully, recheck in 1 week.
538 update_option( 'charitable_usage_tracking_last_checkin', time() );
539 return true;
540 } else {
541 // If we have failed, recheck in 24 hours.
542 update_option( 'charitable_usage_tracking_last_checkin', time() + 86400 );
543 return false;
544 }
545 }
546
547 /**
548 * Send tracking data.
549 *
550 * @since 1.8.4
551 *
552 * @param boolean $override Override usage_optin_allowed.
553 * @param boolean $ignore_last_checkin Ignore last checkin flag.
554 * @return boolean
555 */
556 public function send_tracking_checkin( $override = false, $ignore_last_checkin = false ) {
557
558 if ( defined( 'CHARITABLE_DEBUG_USAGE' ) && CHARITABLE_DEBUG_USAGE ) { // phpcs:disable
559 // phpcs:disable
560 if ( charitable_is_debug() ) {
561 error_log('send_tracking_checkin');
562 }
563 // phpcs:enable
564 }
565
566 if ( defined( 'CHARITABLE_DEBUG_USAGE' ) && CHARITABLE_DEBUG_USAGE ) { // phpcs:disable
567 // phpcs:disable
568 if ( charitable_is_debug() ) {
569 error_log( 'send_checkin' );
570 error_log( $override );
571 error_log( $ignore_last_checkin );
572 error_log( 'tracking allowed' );
573 error_log( $this->usage_optin_allowed() );
574 }
575 // phpcs:enable
576 }
577
578 if ( ! $this->tracking_allowed() && ! $override ) {
579 if ( defined( 'CHARITABLE_DEBUG_USAGE' ) && CHARITABLE_DEBUG_USAGE ) { // phpcs:disable
580 // phpcs:disable
581 if ( charitable_is_debug() ) {
582 error_log( 'charitable tracking not allowed' );
583 }
584 // phpcs:enable
585 }
586 return false;
587 }
588
589 // Send a maximum of once per week.
590 $last_send = get_option( 'charitable_tracking_last_checkin' );
591 if ( is_numeric( $last_send ) && $last_send > strtotime( '-1 week' ) && ! $ignore_last_checkin ) {
592 if ( defined( 'CHARITABLE_DEBUG_USAGE' ) && CHARITABLE_DEBUG_USAGE ) { // phpcs:disable
593 // phpcs:disable
594 if ( charitable_is_debug() ) {
595 error_log('charitable tracking not allowed because of last checkin');
596 }
597 // phpcs:enable
598 }
599 return false;
600 }
601
602 $charitable_object = charitable();
603 $charitable_version = $charitable_object !== null ? charitable()->get_version() : '';
604
605 $request = wp_remote_post(
606 'https://tracking.wpcharitable.com/capture',
607 array(
608 'method' => 'POST',
609 'timeout' => 15,
610 'redirection' => 5,
611 'httpversion' => '1.1',
612 'blocking' => true,
613 'sslverify' => false,
614 'body' => $this->get_tracking_data(),
615 'user-agent' => 'GenericTrackingClient/1.0',
616 )
617 );
618
619 if ( defined( 'CHARITABLE_DEBUG_USAGE' ) && CHARITABLE_DEBUG_USAGE ) { // phpcs:disable
620 // phpcs:disable
621 if ( charitable_is_debug() ) {
622 error_log( print_r( $request, true ) );
623 error_log( print_r( $last_send, true ) );
624 error_log( print_r( $charitable_version, true ) );
625 error_log( print_r( $this->get_tracking_data(), true ) );
626 }
627 }
628
629 if ( ! is_wp_error( $request ) ) {
630 // If we have completed successfully, recheck in 1 week.
631 update_option( 'charitable_usage_tracking_last_checkin', time() );
632 return true;
633 } else {
634 // If we have failed, recheck in 24 hours.
635 update_option( 'charitable_usage_tracking_last_checkin', time() + 86400 );
636 return false;
637 }
638 }
639
640 /**
641 * Check if optin usage tracking is allowed.
642 *
643 * @since 1.8.4
644 *
645 * @return boolean
646 */
647 private function usage_optin_allowed() {
648
649 if ( defined( 'CHARITABLE_DISABLE_OPTIN_USAGE' ) && CHARITABLE_DISABLE_OPTIN_USAGE ) {
650 return true;
651 }
652
653 return (bool) apply_filters( 'charitable_usage_tracking', charitable_get_usage_tracking_setting() );
654 }
655
656 /**
657 * Check if tracking is allowed.
658 *
659 * @since 1.8.4
660 *
661 * @return boolean
662 */
663 private function tracking_allowed() {
664
665 if ( defined( 'CHARITABLE_DISABLE_TRACKING' ) && CHARITABLE_DISABLE_TRACKING ) {
666 return true;
667 }
668
669 if ( ! $this->environment_allows_tracking() ) {
670 return false;
671 }
672
673 return (bool) apply_filters( 'charitable_usage_tracking', charitable_get_usage_tracking_setting() );
674 }
675
676 /**
677 * Whether the environment allows sending telemetry data.
678 *
679 * @since 1.8.4
680 *
681 * @return bool
682 */
683 private function environment_allows_tracking() {
684
685 if ( function_exists( 'wp_get_environment_type' ) && 'staging' === wp_get_environment_type() ) {
686 return false;
687 }
688
689 return true;
690 }
691
692 /**
693 * Schedule send tracking data event.
694 *
695 * @since 1.8.4
696 *
697 * @return void
698 */
699 public function schedule_send() {
700 if ( ! wp_next_scheduled( 'charitable_usage_tracking_cron' ) ) {
701 $tracking = array();
702 $tracking['day'] = wp_rand( 0, 6 );
703 $tracking['hour'] = wp_rand( 0, 23 );
704 $tracking['minute'] = wp_rand( 0, 59 );
705 $tracking['second'] = wp_rand( 0, 59 );
706 $tracking['offset'] = ( $tracking['day'] * DAY_IN_SECONDS ) +
707 ( $tracking['hour'] * HOUR_IN_SECONDS ) +
708 ( $tracking['minute'] * MINUTE_IN_SECONDS ) +
709 $tracking['second'];
710 $tracking['initsend'] = strtotime( "next sunday" ) + $tracking['offset'];
711
712 wp_schedule_event( $tracking['initsend'], 'weekly', 'charitable_usage_tracking_cron' );
713 update_option( 'charitable_usage_tracking_config', $tracking );
714 }
715 }
716
717 /**
718 * Add schedules.
719 *
720 * @since 1.8.4
721 *
722 * @param array $schedules Available/current schedules.
723 * @return array $schedules Schedules array.
724 */
725 public function add_schedules( $schedules = array() ) {
726 // Adds once weekly to the existing schedules.
727 $schedules['weekly'] = array(
728 'interval' => 604800,
729 'display' => __( 'Once Weekly', 'charitable' ),
730 );
731 return $schedules;
732 }
733
734 /**
735 * Get WP Posts count.
736 *
737 * @since 1.8.4
738 *
739 * @return array $wp_post_count WP Posts count.
740 */
741 public function get_wp_posts() {
742 global $wpdb;
743
744 $wp_post_count = 0;
745
746 $results = $wpdb->get_var( // phpcs:ignore
747 "SELECT COUNT(`ID`) `hits`
748 FROM {$wpdb->posts}
749 WHERE `post_type` = 'post' AND `post_status` = 'publish';"
750 );
751 if ( ! empty( $results ) ) {
752 $wp_post_count = $results;
753 }
754
755 return $wp_post_count;
756 }
757
758 /**
759 * Get WP Pages count.
760 *
761 * @since 1.8.4
762 *
763 * @return array $wp_pages_count WP Pages count.
764 */
765 public function get_wp_pages() {
766 global $wpdb;
767
768 $wp_pages_count = 0;
769
770 $results = $wpdb->get_var( // phpcs:ignore
771 "SELECT COUNT(`ID`) `hits`
772 FROM {$wpdb->posts}
773 WHERE `post_type` = 'page' AND `post_status` = 'publish';"
774 );
775 if ( ! empty( $results ) ) {
776 $wp_pages_count = $results;
777 }
778
779 return $wp_pages_count;
780 }
781
782 /**
783 * Insert time for first campaign.
784 *
785 * @since 1.8.4.5
786 *
787 * @param string $insert_or_update Insert or update.
788 * @param int $campaign_id Campaign ID.
789 * @param array $data Data.
790 * @param object $object Object.
791 *
792 * @return void
793 */
794 public function insert_time_to_first_campaign( $insert_or_update, $campaign_id, $data, $object ) {
795 global $wpdb;
796
797 // Only do this for inserts.
798 if ( 'insert' !== $insert_or_update ) {
799 return;
800 }
801
802 $first_campaign = get_option( 'charitable_first_campaign' );
803
804 if ( ! $first_campaign ) {
805 $first_campaign = time();
806 update_option( 'charitable_first_campaign', $first_campaign );
807 }
808 }
809
810 /**
811 * Insert time for first donation.
812 *
813 * @since 1.8.4.5
814 *
815 * @param int $donation_id Donation ID.
816 * @param object $object Charitable_Donation_Processor Object.
817 *
818 * @return void
819 */
820 public function insert_time_to_first_donation( $donation_id, $object ) {
821 global $wpdb;
822
823 $first_donation = get_option( 'charitable_first_donation' );
824
825 if ( ! $first_donation ) {
826 $first_donation = time();
827 update_option( 'charitable_first_donation', $first_donation );
828 }
829 }
830
831 /**
832 * Get block count summation.
833 *
834 * @since 1.8.4
835 *
836 * @return array $blocks_usage_sum Block usage summation.
837 */
838 public function block_count_summation() {
839 // Get all _wpchar_block_usage data.
840 global $wpdb;
841
842 $tablename = $wpdb->prefix . 'postmeta';
843 $sql = "SELECT meta_value FROM $tablename";
844 $sql .= ' WHERE meta_key = %s';
845 $safe_sql = $wpdb->prepare( $sql, '_wpchar_block_usage' ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
846 $results = $wpdb->get_results( $safe_sql ); // phpcs:ignore
847
848 $blocks_usage_sum = array();
849
850 // Sum all block usage data.
851 if ( $results ) {
852 foreach ( $results as $result ) {
853 if ( $result->meta_value ) {
854 $page_usage_data = maybe_unserialize( $result->meta_value );
855 if ( is_array( $page_usage_data ) ) {
856 foreach ( $page_usage_data as $type => $value ) {
857 if ( array_key_exists( $type, $blocks_usage_sum ) ) {
858 // If set.
859 $blocks_usage_sum[ $type ] = array(
860 'name' => $blocks_usage_sum[ $type ]['name'],
861 'count' => $blocks_usage_sum[ $type ]['count'] + $value['count'], // Sum count.
862 );
863 }
864
865 if ( ! array_key_exists( $type, $blocks_usage_sum ) ) {
866 // If block type is not set.
867 $blocks_usage_sum[ $type ] = $value;
868 }
869 }
870 }
871 }
872 }
873 }
874
875 return $blocks_usage_sum;
876 }
877
878 /**
879 * Check if WooCommerce is active or not.
880 *
881 * @since 1.8.4
882 *
883 * @return boolean true|false Return if WC active.
884 */
885 public function check_if_wc_active() {
886 // Check if WooCommerce is active.
887 return in_array( 'woocommerce/woocommerce.php', apply_filters( 'active_plugins', get_option( 'active_plugins' ) ) );
888 }
889
890 /**
891 * Get the AID for the site.
892 *
893 * @since 1.8.4
894 *
895 * @return string The AID for the site.
896 */
897 private function get_site_aid() {
898 // Check if the AID already exists in the database.
899 $aid = get_option( 'charitable_site_tracking_aid' );
900
901 if ( $aid === false ) {
902 // If it doesn't exist, generate a new one.
903 $site_url = get_site_url(); // Get the site URL.
904 $random_salt = wp_generate_password( 20, false, false ); // Generate a random salt.
905 // Create a hash based on the site URL and salt.
906 $aid = hash( 'sha256', $site_url . $random_salt );
907
908 // Save the generated AID in the database.
909 update_option( 'charitable_site_tracking_aid', $aid );
910 }
911
912 return $aid;
913 }
914
915 /**
916 * Returns and/or create the single instance of this class.
917 *
918 * @since 1.8.4
919 *
920 * @return Charitable_Tracking
921 */
922 public static function get_instance() {
923 if ( is_null( self::$instance ) ) {
924 self::$instance = new self();
925 }
926
927 return self::$instance;
928 }
929 }
930
931
932 }
933