PluginProbe ʕ •ᴥ•ʔ
WP STAGING – WordPress Backups, Restore, Migration & Clone / 3.0.2
WP STAGING – WordPress Backups, Restore, Migration & Clone v3.0.2
4.11.2 4.11.1 4.11.0 4.10.0 4.9.5 4.9.4 4.9.3 4.9.2 4.9.1 4.9.0 4.8.1 trunk 3.0.0 3.0.1 3.0.2 3.0.3 3.0.4 3.0.5 3.0.6 3.1.0 3.1.1 3.1.2 3.1.3 3.1.4 3.10.0 3.2.0 3.3.1 3.3.2 3.3.3 3.4.1 3.4.3 3.5.0 3.6.0 3.7.1 3.8.0 3.8.1 3.8.2 3.8.3 3.8.4 3.8.5 3.8.6 3.8.7 3.9.0 3.9.1 3.9.2 3.9.3 3.9.4 4.0.0 4.1.0 4.1.1 4.1.2 4.1.3 4.1.4 4.2.0 4.2.1 4.3.0 4.3.1 4.3.2 4.4.0 4.5.0 4.6.0 4.7.0 4.7.1 4.7.2 4.7.3 4.8.0
wp-staging / Framework / Analytics / AnalyticsSender.php
wp-staging / Framework / Analytics Last commit date
Actions 3 years ago AnalyticsCleanup.php 4 years ago AnalyticsConsent.php 3 years ago AnalyticsEventDto.php 3 years ago AnalyticsSender.php 4 years ago WithAnalyticsAPI.php 4 years ago WithAnalyticsSiteInfo.php 3 years ago
AnalyticsSender.php
176 lines
1 <?php
2
3 namespace WPStaging\Framework\Analytics;
4
5 class AnalyticsSender
6 {
7 use WithAnalyticsAPI;
8
9 protected $consent;
10
11 private $corruptSettingsNotice;
12
13 public function __construct(AnalyticsConsent $consent)
14 {
15 $this->consent = $consent;
16 }
17
18 public function maybeSend()
19 {
20 // Early bail: Do not run on AJAX requests.
21 if (defined('DOING_AJAX') && DOING_AJAX) {
22 return;
23 }
24
25 // We store the analytics sending time at "wpstg_settings"
26 // since this runs on every request, and it's an autoloaded option.
27 // Also, the value we need to store in it is small.
28 $settings = get_option("wpstg_settings", []);
29
30 // convert settings from type object to array
31 if (is_object($settings)) {
32 $settings = json_decode(json_encode($settings), true);
33 }
34
35 // If still $settings is not array, bail
36 if (!is_array($settings)) {
37 return;
38 }
39
40 // Interval to wait before sending events.
41 $interval = 15 * MINUTE_IN_SECONDS;
42
43 // Early bail: Sent not so long ago.
44 if (isset($settings['lastAnalyticsSend']) && time() - $settings['lastAnalyticsSend'] - $interval < 0) {
45 return;
46 }
47
48 $settings['lastAnalyticsSend'] = time();
49
50 if (!update_option('wpstg_settings', $settings)) {
51 \WPStaging\functions\debug_log('WP STAGING: Could not update Analytics last sent time.', 'debug');
52 };
53
54 $this->sendAnalytics();
55 }
56
57 public function sendAnalytics()
58 {
59 global $wpdb;
60
61 $eventOptions = $wpdb->get_results("SELECT * FROM $wpdb->options WHERE `option_name` LIKE 'wpstg_analytics_event_%' LIMIT 0, 20");
62
63 // Nothing to send.
64 if (empty($eventOptions)) {
65 return;
66 }
67
68 // Early bail: User has not given consent to send analytics
69 if (!$this->consent->hasUserConsent()) {
70 return;
71 }
72
73 // Format the events to the expected format
74 $events = array_map(function ($eventOption) {
75 return json_decode($eventOption->option_value);
76 }, $eventOptions);
77
78 $this->setStaleEvents($events);
79
80 // Filter the events to send only those that are ready to be sent
81 $events = array_filter($events, function ($event) {
82 return $event->ready_to_send;
83 });
84
85 // Early bail: No events ready to be sent
86 if (empty($events)) {
87 return;
88 }
89
90 // Convert true to 1 and false to 0 for MySQL TinyInt
91 foreach ($events as &$event) {
92 foreach ($event as $property => &$value) {
93 if (is_bool($value)) {
94 $event->$property = (int)$value;
95 } elseif ($property === 'site_info') {
96 $siteInfo = &$value;
97
98 foreach ($siteInfo as $siteInfoProperty => &$siteInfoValue) {
99 if (is_bool($siteInfoValue)) {
100 $siteInfo->$siteInfoProperty = (int)$siteInfoValue;
101 }
102 }
103 }
104 }
105 }
106
107 // Delete the events, regardless of whether it succeeded or failed to send.
108 // This prevents events from hanging and being sent every time if they are in an invalid format or something goes wrong.
109 $idsToDelete = implode(',', array_map(function ($eventOption) {
110 return $eventOption->option_id;
111 }, $eventOptions));
112
113 if (!$wpdb->query("DELETE FROM $wpdb->options WHERE `option_id` IN ($idsToDelete)")) {
114 \WPStaging\functions\debug_log('WP STAGING Analytics Delete Sent Events Error: ' . $wpdb->last_error);
115 }
116
117 $body = wp_json_encode([
118 'events' => $events,
119 'site_hash' => $this->getSiteHash(),
120 ]);
121
122 $url = $this->getApiUrl('events');
123
124 // Early bail: Do not dispatch events when in dev mode, unless allowed.
125 if (defined('WPSTG_DEV') && WPSTG_DEV) {
126 if (!defined('WPSTG_DEV_SEND_ANALYTICS') || defined('WPSTG_DEV_SEND_ANALYTICS') && !WPSTG_DEV_SEND_ANALYTICS) {
127 return;
128 }
129 }
130 $response = wp_remote_post($url, [
131 'method' => 'POST',
132 'headers' => ['Content-Type' => 'application/json; charset=utf-8'],
133 'body' => $body,
134 'data_format' => 'body',
135 'timeout' => 10,
136 'redirection' => 5,
137 'httpversion' => '1.0',
138 'blocking' => true,
139 'sslverify' => false,
140 ]);
141
142 if (is_wp_error($response) || wp_remote_retrieve_response_code($response) !== 200) {
143 if (wp_remote_retrieve_response_code($response) == 412) {
144 // The site hash does not exist in the Analytics database. We need to ask for consent again.
145 if ($this->consent->hasUserConsent()) {
146 try {
147 $this->consent->giveConsent();
148 } catch (\Exception $e) {
149 // We could not re-validate the consent.
150 // Let's ask it again to the user, which will handle notices and a scenario of connection failure.
151 $this->consent->invalidateConsent();
152 }
153 }
154 }
155
156 $errorMessage = is_wp_error($response) ? $response->get_error_message() : wp_remote_retrieve_body($response);
157 \WPStaging\functions\debug_log('WP STAGING Analytics Send Error: ' . $errorMessage);
158 }
159 }
160
161 /**
162 * Mark as stale the events that started longer than 1 day ago but isn't ready to send yet
163 *
164 * @param $events
165 */
166 protected function setStaleEvents(&$events)
167 {
168 foreach ($events as &$event) {
169 if (!$event->ready_to_send && $event->start_time < time() - 1 * DAY_IN_SECONDS) {
170 $event->ready_to_send = true;
171 $event->is_stale = true;
172 }
173 }
174 }
175 }
176