PluginProbe ʕ •ᴥ•ʔ
Independent Analytics – WordPress Analytics Plugin / 1.25.0
Independent Analytics – WordPress Analytics Plugin v1.25.0
2.15.5 2.15.4 2.15.3 2.15.2 2.15.1 2.15.0 2.14.10 trunk 1.1 1.10 1.10.1 1.11 1.12 1.13 1.14 1.15 1.16 1.17 1.17.1 1.17.2 1.17.3 1.17.4 1.18 1.18.1 1.19.0 1.19.1 1.2 1.20.0 1.21.0 1.22.0 1.22.1 1.23.0 1.23.1 1.24.0 1.24.1 1.25.0 1.25.1 1.26.0 1.27.0 1.28.0 1.28.1 1.28.2 1.28.3 1.29.0 1.3 1.30.0 1.30.1 1.4 1.5 1.6 1.7 1.8 1.9 2.0.0 2.0.1 2.1.4 2.1.5 2.1.6 2.10.0 2.10.1 2.10.2 2.10.3 2.10.4 2.11.0 2.11.1 2.11.10 2.11.2 2.11.3 2.11.4 2.11.5 2.11.6 2.11.7 2.11.8 2.11.9 2.12.0 2.12.1 2.12.2 2.13.1 2.13.2 2.13.5 2.13.6 2.14.0 2.14.1 2.14.2 2.14.4 2.14.6 2.14.7 2.14.8 2.14.9 2.2.0 2.2.1 2.3.1 2.3.2 2.4.2 2.4.3 2.5.0 2.5.1 2.6.0 2.6.1 2.6.2 2.6.3 2.6.4 2.7.0 2.7.1 2.7.2 2.7.3 2.8.2 2.8.3 2.8.4 2.8.5 2.8.6 2.8.7 2.8.8 2.8.9 2.9.2 2.9.3 2.9.4 2.9.5 2.9.6 2.9.7
independent-analytics / IAWP / View.php
independent-analytics / IAWP Last commit date
AJAX 3 years ago Date_Range 3 years ago Interval 3 years ago Menu_Bar_Stats 3 years ago Migrations 3 years ago Models 3 years ago Queries 3 years ago Statistics 3 years ago Tables 3 years ago Utils 3 years ago Campaign_Builder.php 3 years ago Capability_Manager.php 3 years ago Chart.php 3 years ago Chart_Geo.php 3 years ago Chart_SVG.php 3 years ago Dashboard_Options.php 3 years ago Dashboard_Widget.php 3 years ago Email_Reports.php 3 years ago Filters.php 3 years ago Geo_Database.php 3 years ago Geo_Database_Download_Job.php 3 years ago Health_Check.php 3 years ago Illuminate_Builder.php 3 years ago Independent_Analytics.php 3 years ago Known_Referrers.php 3 years ago PDF.php 3 years ago Query.php 3 years ago Quick_Stats.php 3 years ago REST_API.php 3 years ago Real_Time.php 3 years ago Reset_Database.php 3 years ago Resource_Identifier.php 3 years ago Settings.php 3 years ago Sort_Configuration.php 3 years ago Track_Resource_Changes.php 3 years ago View.php 3 years ago View_Counter.php 3 years ago WP_Option_Cache_Bust.php 3 years ago WooCommerce_Order.php 3 years ago
View.php
281 lines
1 <?php
2
3 namespace IAWP_SCOPED\IAWP;
4
5 use IAWP_SCOPED\IAWP\Models\Page_Author_Archive;
6 use IAWP_SCOPED\IAWP\Models\Page_Date_Archive;
7 use IAWP_SCOPED\IAWP\Models\Page_Home;
8 use IAWP_SCOPED\IAWP\Models\Page_Not_Found;
9 use IAWP_SCOPED\IAWP\Models\Page_Post_Type_Archive;
10 use IAWP_SCOPED\IAWP\Models\Page_Search;
11 use IAWP_SCOPED\IAWP\Models\Page_Singular;
12 use IAWP_SCOPED\IAWP\Models\Page_Term_Archive;
13 use IAWP_SCOPED\IAWP\Models\Visitor;
14 use IAWP_SCOPED\IAWP\Utils\String_Util;
15 use IAWP_SCOPED\IAWP\Utils\URL;
16 class View
17 {
18 private $payload;
19 private $referrer_url;
20 private $visitor;
21 private $campaign_fields;
22 private $viewed_at;
23 private $resource;
24 private $session;
25 /**
26 * @param array $payload
27 * @param string|null $referrer_url
28 * @param Visitor $visitor
29 * @param array $campaign_fields
30 * @param \DateTime|null $viewed_at
31 */
32 public function __construct(array $payload, ?string $referrer_url, Visitor $visitor, array $campaign_fields, ?\DateTime $viewed_at = null)
33 {
34 $this->payload = $payload;
35 $this->referrer_url = \trim($referrer_url);
36 $this->visitor = $visitor;
37 $this->campaign_fields = $campaign_fields;
38 $this->viewed_at = $viewed_at instanceof \DateTime ? $viewed_at : new \DateTime();
39 $this->resource = $this->fetch_or_create_resource();
40 $this->session = $this->fetch_or_create_session();
41 $view_id = $this->create_view();
42 $this->link_with_previous_view($view_id);
43 $this->set_sessions_initial_view($view_id);
44 $this->set_sessions_final_view($view_id);
45 }
46 private function viewed_at() : string
47 {
48 return $this->viewed_at->format('Y-m-d H:i:s');
49 }
50 private function link_with_previous_view($view_id) : void
51 {
52 global $wpdb;
53 $views_tables = Query::get_table_name(Query::VIEWS);
54 $session = Query::query('sessions/get_session', ['session_id' => $this->session])->row();
55 if (\is_null($session)) {
56 return;
57 }
58 $final_view_id = $session->final_view_id;
59 $initial_view_id = $session->initial_view_id;
60 if (!\is_null($final_view_id)) {
61 $wpdb->update($views_tables, ['next_view_id' => $view_id, 'next_viewed_at' => $this->viewed_at()], ['id' => $final_view_id]);
62 } elseif (!\is_null($initial_view_id)) {
63 $wpdb->update($views_tables, ['next_view_id' => $view_id, 'next_viewed_at' => $this->viewed_at()], ['id' => $initial_view_id]);
64 }
65 }
66 private function set_sessions_initial_view(int $view_id)
67 {
68 global $wpdb;
69 $sessions_table = Query::get_table_name(Query::SESSIONS);
70 $wpdb->query($wpdb->prepare("UPDATE {$sessions_table} SET initial_view_id = %d WHERE session_id = %d AND initial_view_id IS NULL", $view_id, $this->session));
71 }
72 private function set_sessions_final_view(int $view_id)
73 {
74 global $wpdb;
75 $sessions_table = Query::get_table_name(Query::SESSIONS);
76 $wpdb->query($wpdb->prepare("\n UPDATE {$sessions_table} AS sessions\n SET\n sessions.final_view_id = %d,\n sessions.ended_at = %s\n WHERE sessions.session_id = %d AND sessions.initial_view_id IS NOT NULL AND sessions.initial_view_id != %d\n ", $view_id, $this->viewed_at(), $this->session, $view_id));
77 }
78 private function create_view() : ?int
79 {
80 $viewed_at = $this->viewed_at();
81 return Query::query('create_view', ['resource_id' => $this->resource, 'viewed_at' => $viewed_at, 'page' => $this->payload['page'], 'session_id' => $this->session])->last_inserted_id();
82 }
83 private function fetch_resource()
84 {
85 global $wpdb;
86 $resources_table = Query::get_table_name(Query::RESOURCES);
87 $query = '';
88 $payload_copy = \array_merge($this->payload);
89 unset($payload_copy['page']);
90 switch ($payload_copy['resource']) {
91 case 'singular':
92 $query = $wpdb->prepare("SELECT * FROM {$resources_table} WHERE resource = %s AND singular_id = %d", $payload_copy['resource'], $payload_copy['singular_id']);
93 break;
94 case 'author_archive':
95 $query = $wpdb->prepare("SELECT * FROM {$resources_table} WHERE resource = %s AND author_id = %d", $payload_copy['resource'], $payload_copy['author_id']);
96 break;
97 case 'date_archive':
98 $query = $wpdb->prepare("SELECT * FROM {$resources_table} WHERE resource = %s AND date_archive = %s", $payload_copy['resource'], $payload_copy['date_archive']);
99 break;
100 case 'post_type_archive':
101 $query = $wpdb->prepare("SELECT * FROM {$resources_table} WHERE resource = %s AND post_type = %s", $payload_copy['resource'], $payload_copy['post_type']);
102 break;
103 case 'term_archive':
104 $query = $wpdb->prepare("SELECT * FROM {$resources_table} WHERE resource = %s AND term_id = %s", $payload_copy['resource'], $payload_copy['term_id']);
105 break;
106 case 'search':
107 $query = $wpdb->prepare("SELECT * FROM {$resources_table} WHERE resource = %s AND search_query = %s", $payload_copy['resource'], $payload_copy['search_query']);
108 break;
109 case 'home':
110 $query = $wpdb->prepare("SELECT * FROM {$resources_table} WHERE resource = %s ", $payload_copy['resource']);
111 break;
112 case '404':
113 $query = $wpdb->prepare("SELECT * FROM {$resources_table} WHERE resource = %s AND not_found_url = %s", $payload_copy['resource'], $payload_copy['not_found_url']);
114 break;
115 }
116 $resource = $wpdb->get_row($query);
117 if (\is_null($resource)) {
118 return null;
119 }
120 return $resource;
121 }
122 private function fetch_or_create_resource() : int
123 {
124 global $wpdb;
125 $resources_table = Query::get_table_name(Query::RESOURCES);
126 $resource = $this->fetch_resource();
127 if (\is_null($resource)) {
128 $payload_copy = \array_merge($this->payload);
129 unset($payload_copy['page']);
130 $wpdb->insert($resources_table, $payload_copy);
131 $resource = $this->fetch_resource();
132 }
133 // Todo - This probably shouldn't happen here... A call should be make to the page and then the page should
134 // know if it's a page type that needs to be cached or not.
135 switch ($resource->resource) {
136 case 'singular':
137 (new Page_Singular($resource))->update_cache();
138 break;
139 case 'author_archive':
140 (new Page_Author_Archive($resource))->update_cache();
141 break;
142 case 'post_type_archive':
143 (new Page_Post_Type_Archive($resource))->update_cache();
144 break;
145 case 'term_archive':
146 (new Page_Term_Archive($resource))->update_cache();
147 break;
148 case 'home':
149 (new Page_Home($resource))->update_cache();
150 break;
151 case 'date_archive':
152 (new Page_Date_Archive($resource))->update_cache();
153 break;
154 case '404':
155 (new Page_Not_Found($resource))->update_cache();
156 break;
157 case 'search':
158 (new Page_Search($resource))->update_cache();
159 break;
160 }
161 return $resource->id;
162 }
163 /**
164 * @param string|null $referrer_url
165 *
166 * @return bool
167 */
168 private function from_internal_page(?string $referrer_url) : bool
169 {
170 return !empty($referrer_url) && String_Util::str_starts_with(\strtolower($referrer_url), \strtolower(\site_url()));
171 }
172 /**
173 * @return int|null ID of the session that should be used for this view
174 */
175 private function fetch_or_create_session() : ?int
176 {
177 $from_external_page = !$this->from_internal_page($this->referrer_url);
178 $session = Query::query('sessions/get_current_session', ['visitor_id' => $this->visitor->id()])->row();
179 if (\is_null($session)) {
180 return $this->create_session();
181 }
182 $same_referrer = $this->fetch_referrer() === $session->referrer_id;
183 $same_resource = \intval($this->fetch_resource()->id) === $this->fetch_last_viewed_resource();
184 $same_as_previous_view = $same_referrer && $same_resource;
185 // The goal here is to prevent a page refresh from creating another session
186 if ($from_external_page && !$same_as_previous_view) {
187 return $this->create_session();
188 }
189 return $session->session_id;
190 }
191 /**
192 * @return int ID of newly created session
193 */
194 public function create_session() : int
195 {
196 $created_at = $this->viewed_at();
197 return Query::query('sessions/create_session', ['visitor_id' => $this->visitor->id(), 'referrer_id' => $this->fetch_or_create_referrer(), 'campaign_id' => $this->get_campaign(), 'created_at' => $created_at])->last_inserted_id();
198 }
199 /**
200 * Fetch the last view, if any.
201 *
202 * @return int|null
203 */
204 public function fetch_last_viewed_resource() : ?int
205 {
206 global $wpdb;
207 $views_table = Query::get_table_name(Query::VIEWS);
208 $session = Query::query('sessions/get_current_session', ['visitor_id' => $this->visitor->id()])->row();
209 if (\is_null($session)) {
210 return null;
211 }
212 $view = $wpdb->get_row($wpdb->prepare("\n SELECT * FROM {$views_table} WHERE session_id = %d ORDER BY viewed_at DESC LIMIT 1\n ", $session->session_id));
213 if (\is_null($view)) {
214 return null;
215 }
216 return $view->resource_id;
217 }
218 /**
219 * @return int|null ID of referrer, if any
220 */
221 public function fetch_referrer() : ?int
222 {
223 if (!isset($this->referrer_url) || \strlen($this->referrer_url) === 0) {
224 return null;
225 }
226 $url = new URL($this->referrer_url);
227 if (!$url->is_valid_url()) {
228 return null;
229 }
230 if ($this->from_internal_page($this->referrer_url)) {
231 return null;
232 }
233 $referrer = Query::query('get_referrer', ['domain' => $url->get_domain()])->row();
234 if (\is_null($referrer)) {
235 return null;
236 }
237 return $referrer->id;
238 }
239 private function fetch_or_create_referrer() : ?int
240 {
241 $referrer_id = $this->fetch_referrer();
242 if (!\is_null($referrer_id)) {
243 return $referrer_id;
244 }
245 $url = new URL($this->referrer_url);
246 if (!$url->is_valid_url()) {
247 return null;
248 }
249 if ($this->from_internal_page($this->referrer_url)) {
250 return null;
251 }
252 Query::query('create_referrer', ['domain' => $url->get_domain()]);
253 return $this->fetch_referrer();
254 }
255 private function get_campaign() : ?int
256 {
257 global $wpdb;
258 $required_fields = ['utm_source', 'utm_medium', 'utm_campaign'];
259 $valid = \true;
260 foreach ($required_fields as $field) {
261 if (!isset($this->campaign_fields[$field])) {
262 $valid = \false;
263 }
264 }
265 if (!$valid) {
266 return null;
267 }
268 $campaigns_table = Query::get_table_name(Query::CAMPAIGNS);
269 $campaign = $wpdb->get_row($wpdb->prepare("SELECT * FROM {$campaigns_table} WHERE utm_source = %s AND utm_medium = %s AND utm_campaign = %s AND (utm_term = %s OR (%d = 0 AND utm_term IS NULL)) AND (utm_content = %s OR (%d = 0 AND utm_content IS NULL))", $this->campaign_fields['utm_source'], $this->campaign_fields['utm_medium'], $this->campaign_fields['utm_campaign'], $this->campaign_fields['utm_term'], isset($this->campaign_fields['utm_term']) ? 1 : 0, $this->campaign_fields['utm_content'], isset($this->campaign_fields['utm_content']) ? 1 : 0));
270 if (!\is_null($campaign)) {
271 return $campaign->campaign_id;
272 }
273 $wpdb->insert($campaigns_table, ['utm_source' => $this->campaign_fields['utm_source'], 'utm_medium' => $this->campaign_fields['utm_medium'], 'utm_campaign' => $this->campaign_fields['utm_campaign'], 'utm_term' => $this->campaign_fields['utm_term'], 'utm_content' => $this->campaign_fields['utm_content']]);
274 $campaign = $wpdb->get_row($wpdb->prepare("SELECT * FROM {$campaigns_table} WHERE utm_source = %s AND utm_medium = %s AND utm_campaign = %s AND (utm_term = %s OR (%d = 0 AND utm_term IS NULL)) AND (utm_content = %s OR (%d = 0 AND utm_content IS NULL))", $this->campaign_fields['utm_source'], $this->campaign_fields['utm_medium'], $this->campaign_fields['utm_campaign'], $this->campaign_fields['utm_term'], isset($this->campaign_fields['utm_term']) ? 1 : 0, $this->campaign_fields['utm_content'], isset($this->campaign_fields['utm_content']) ? 1 : 0));
275 if (!\is_null($campaign)) {
276 return $campaign->campaign_id;
277 }
278 return null;
279 }
280 }
281