PluginProbe ʕ •ᴥ•ʔ
Independent Analytics – WordPress Analytics Plugin / 1.27.0
Independent Analytics – WordPress Analytics Plugin v1.27.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 City_To_Country_Converter.php 3 years ago Dashboard_Options.php 3 years ago Dashboard_Widget.php 3 years ago Email_Chart.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 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 /**
47 * @return int ID of newly created session
48 */
49 public function create_session() : int
50 {
51 $created_at = $this->viewed_at();
52 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();
53 }
54 /**
55 * Fetch the last view, if any.
56 *
57 * @return int|null
58 */
59 public function fetch_last_viewed_resource() : ?int
60 {
61 global $wpdb;
62 $views_table = Query::get_table_name(Query::VIEWS);
63 $session = Query::query('sessions/get_current_session', ['visitor_id' => $this->visitor->id()])->row();
64 if (\is_null($session)) {
65 return null;
66 }
67 $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));
68 if (\is_null($view)) {
69 return null;
70 }
71 return $view->resource_id;
72 }
73 /**
74 * @return int|null ID of referrer, if any
75 */
76 public function fetch_referrer() : ?int
77 {
78 if (!isset($this->referrer_url) || \strlen($this->referrer_url) === 0) {
79 return null;
80 }
81 $url = new URL($this->referrer_url);
82 if (!$url->is_valid_url()) {
83 return null;
84 }
85 if ($this->from_internal_page($this->referrer_url)) {
86 return null;
87 }
88 $referrer = Query::query('get_referrer', ['domain' => $url->get_domain()])->row();
89 if (\is_null($referrer)) {
90 return null;
91 }
92 return $referrer->id;
93 }
94 private function viewed_at() : string
95 {
96 return $this->viewed_at->format('Y-m-d H:i:s');
97 }
98 private function link_with_previous_view($view_id) : void
99 {
100 global $wpdb;
101 $views_tables = Query::get_table_name(Query::VIEWS);
102 $session = Query::query('sessions/get_session', ['session_id' => $this->session])->row();
103 if (\is_null($session)) {
104 return;
105 }
106 $final_view_id = $session->final_view_id;
107 $initial_view_id = $session->initial_view_id;
108 if (!\is_null($final_view_id)) {
109 $wpdb->update($views_tables, ['next_view_id' => $view_id, 'next_viewed_at' => $this->viewed_at()], ['id' => $final_view_id]);
110 } elseif (!\is_null($initial_view_id)) {
111 $wpdb->update($views_tables, ['next_view_id' => $view_id, 'next_viewed_at' => $this->viewed_at()], ['id' => $initial_view_id]);
112 }
113 }
114 private function set_sessions_initial_view(int $view_id)
115 {
116 global $wpdb;
117 $sessions_table = Query::get_table_name(Query::SESSIONS);
118 $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));
119 }
120 private function set_sessions_final_view(int $view_id)
121 {
122 global $wpdb;
123 $sessions_table = Query::get_table_name(Query::SESSIONS);
124 $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));
125 }
126 private function create_view() : ?int
127 {
128 $viewed_at = $this->viewed_at();
129 return Query::query('create_view', ['resource_id' => $this->resource, 'viewed_at' => $viewed_at, 'page' => $this->payload['page'], 'session_id' => $this->session])->last_inserted_id();
130 }
131 private function fetch_resource()
132 {
133 global $wpdb;
134 $resources_table = Query::get_table_name(Query::RESOURCES);
135 $query = '';
136 $payload_copy = \array_merge($this->payload);
137 unset($payload_copy['page']);
138 switch ($payload_copy['resource']) {
139 case 'singular':
140 $query = $wpdb->prepare("SELECT * FROM {$resources_table} WHERE resource = %s AND singular_id = %d", $payload_copy['resource'], $payload_copy['singular_id']);
141 break;
142 case 'author_archive':
143 $query = $wpdb->prepare("SELECT * FROM {$resources_table} WHERE resource = %s AND author_id = %d", $payload_copy['resource'], $payload_copy['author_id']);
144 break;
145 case 'date_archive':
146 $query = $wpdb->prepare("SELECT * FROM {$resources_table} WHERE resource = %s AND date_archive = %s", $payload_copy['resource'], $payload_copy['date_archive']);
147 break;
148 case 'post_type_archive':
149 $query = $wpdb->prepare("SELECT * FROM {$resources_table} WHERE resource = %s AND post_type = %s", $payload_copy['resource'], $payload_copy['post_type']);
150 break;
151 case 'term_archive':
152 $query = $wpdb->prepare("SELECT * FROM {$resources_table} WHERE resource = %s AND term_id = %s", $payload_copy['resource'], $payload_copy['term_id']);
153 break;
154 case 'search':
155 $query = $wpdb->prepare("SELECT * FROM {$resources_table} WHERE resource = %s AND search_query = %s", $payload_copy['resource'], $payload_copy['search_query']);
156 break;
157 case 'home':
158 $query = $wpdb->prepare("SELECT * FROM {$resources_table} WHERE resource = %s ", $payload_copy['resource']);
159 break;
160 case '404':
161 $query = $wpdb->prepare("SELECT * FROM {$resources_table} WHERE resource = %s AND not_found_url = %s", $payload_copy['resource'], $payload_copy['not_found_url']);
162 break;
163 }
164 $resource = $wpdb->get_row($query);
165 if (\is_null($resource)) {
166 return null;
167 }
168 return $resource;
169 }
170 private function fetch_or_create_resource() : int
171 {
172 global $wpdb;
173 $resources_table = Query::get_table_name(Query::RESOURCES);
174 $resource = $this->fetch_resource();
175 if (\is_null($resource)) {
176 $payload_copy = \array_merge($this->payload);
177 unset($payload_copy['page']);
178 $wpdb->insert($resources_table, $payload_copy);
179 $resource = $this->fetch_resource();
180 }
181 // Todo - This probably shouldn't happen here... A call should be make to the page and then the page should
182 // know if it's a page type that needs to be cached or not.
183 switch ($resource->resource) {
184 case 'singular':
185 (new Page_Singular($resource))->update_cache();
186 break;
187 case 'author_archive':
188 (new Page_Author_Archive($resource))->update_cache();
189 break;
190 case 'post_type_archive':
191 (new Page_Post_Type_Archive($resource))->update_cache();
192 break;
193 case 'term_archive':
194 (new Page_Term_Archive($resource))->update_cache();
195 break;
196 case 'home':
197 (new Page_Home($resource))->update_cache();
198 break;
199 case 'date_archive':
200 (new Page_Date_Archive($resource))->update_cache();
201 break;
202 case '404':
203 (new Page_Not_Found($resource))->update_cache();
204 break;
205 case 'search':
206 (new Page_Search($resource))->update_cache();
207 break;
208 }
209 return $resource->id;
210 }
211 /**
212 * @param string|null $referrer_url
213 *
214 * @return bool
215 */
216 private function from_internal_page(?string $referrer_url) : bool
217 {
218 return !empty($referrer_url) && String_Util::str_starts_with(\strtolower($referrer_url), \strtolower(\site_url()));
219 }
220 /**
221 * @return int|null ID of the session that should be used for this view
222 */
223 private function fetch_or_create_session() : ?int
224 {
225 $from_external_page = !$this->from_internal_page($this->referrer_url);
226 $session = Query::query('sessions/get_current_session', ['visitor_id' => $this->visitor->id()])->row();
227 if (\is_null($session)) {
228 return $this->create_session();
229 }
230 $same_referrer = $this->fetch_referrer() === $session->referrer_id;
231 $same_resource = \intval($this->fetch_resource()->id) === $this->fetch_last_viewed_resource();
232 $same_as_previous_view = $same_referrer && $same_resource;
233 // The goal here is to prevent a page refresh from creating another session
234 if ($from_external_page && !$same_as_previous_view) {
235 return $this->create_session();
236 }
237 return $session->session_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