PluginProbe ʕ •ᴥ•ʔ
Independent Analytics – WordPress Analytics Plugin / 2.15.0
Independent Analytics – WordPress Analytics Plugin v2.15.0
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 / Admin_Page / Analytics_Page.php
independent-analytics / IAWP / Admin_Page Last commit date
Admin_Page.php 6 months ago Analytics_Page.php 4 days ago Campaign_Builder_Page.php 2 years ago Click_Tracking_Page.php 1 year ago Debug_Page.php 3 months ago Integrations_Pages.php 3 months ago Settings_Page.php 2 years ago Support_Page.php 3 months ago Updates_Page.php 3 months ago Visitor_Page.php 5 months ago
Analytics_Page.php
361 lines
1 <?php
2
3 namespace IAWP\Admin_Page;
4
5 use IAWP\Capability_Manager;
6 use IAWP\Chart;
7 use IAWP\Dashboard_Options;
8 use IAWP\Database;
9 use IAWP\Env;
10 use IAWP\Examiner\Header;
11 use IAWP\Map;
12 use IAWP\Map_Data;
13 use IAWP\Overview\Overview;
14 use IAWP\Plugin_Conflict_Detector;
15 use IAWP\Quick_Stats;
16 use IAWP\RealTime\RealTime;
17 use IAWP\Report_Finder;
18 use IAWP\Tables\Table;
19 use IAWP\Tables\Table_Journeys;
20 use IAWP\Utils\Request;
21 use IAWP\Utils\Security;
22 use IAWPSCOPED\Illuminate\Support\Arr;
23 use IAWPSCOPED\Illuminate\Support\Collection;
24 /** @internal */
25 class Analytics_Page extends \IAWP\Admin_Page\Admin_Page
26 {
27 protected function render_page()
28 {
29 $options = Dashboard_Options::getInstance();
30 $date_rage = $options->get_date_range();
31 $tab = (new Env())->get_tab();
32 $is_showing_skeleton_ui = \true;
33 // Real-time is its own thing
34 if ($tab === 'real-time') {
35 $real_time = new RealTime();
36 $real_time->render_real_time_analytics();
37 return;
38 }
39 // Overview is its own thing
40 if ($tab === 'overview') {
41 $overview = new Overview();
42 echo $overview->get_report_html();
43 $this->notices();
44 return;
45 }
46 // User journeys is a very difference animal
47 if ($tab === 'journeys') {
48 $this->user_journey_interface();
49 return;
50 }
51 $table_class = Env::get_table($tab);
52 $table = new $table_class($options->group());
53 $sort_configuration = $table->sanitize_sort_parameters($options->sort_column(), $options->sort_direction());
54 $hide_unfiltered_statistics = \false;
55 $rows = null;
56 $examiner_model = null;
57 if ($options->is_examiner()) {
58 $rows_class = $table->group()->rows_class();
59 $rows = new $rows_class($options->get_date_range(), $sort_configuration);
60 $id = Request::query_int('examiner');
61 $rows->limit_to($id);
62 $examiner_model = $rows->rows()[0];
63 $hide_unfiltered_statistics = \true;
64 }
65 $statistics_class = $table->group()->statistics_class();
66 $statistics = new $statistics_class($date_rage, $rows, $options->chart_interval());
67 $stats = new Quick_Stats($statistics, \false, $is_showing_skeleton_ui, $hide_unfiltered_statistics);
68 // Never show the map when loading the geo examiner. It'll only ever show a single country anyway.
69 if ($tab === 'geo' && !$options->is_examiner()) {
70 $table_data_class = $table->group()->rows_class();
71 $geo_data = new $table_data_class($date_rage, $table->sanitize_sort_parameters());
72 $map_data = new Map_Data($geo_data->rows());
73 $chart = new Map($map_data->get_country_data(), null, $is_showing_skeleton_ui);
74 } else {
75 $chart = new Chart($statistics, \false, $is_showing_skeleton_ui);
76 }
77 $this->interface($table, $stats, $chart, $examiner_model);
78 }
79 private function user_journey_interface()
80 {
81 $options = Dashboard_Options::getInstance();
82 $table = new Table_Journeys();
83 $sort_configuration = $table->sanitize_sort_parameters('created_at', 'DESC');
84 $header = \IAWPSCOPED\iawp_render('partials.report-header', ['report' => Report_Finder::new()->fetch_current_report(), 'can_edit' => Capability_Manager::can_edit()]);
85 ?>
86 <div data-controller="report"
87 data-report-is-examiner-value="<?php
88 echo $options->is_examiner() ? '1' : '0';
89 ?>"
90 data-report-name-value="<?php
91 echo Security::string($options->report_name());
92 ?>"
93 data-report-report-name-value="<?php
94 echo Security::string($table->group()->singular());
95 ?>"
96 data-report-relative-range-id-value="<?php
97 echo Security::attr($options->relative_range_id());
98 ?>"
99 data-report-exact-start-value="<?php
100 echo Security::attr($options->start());
101 ?>"
102 data-report-exact-end-value="<?php
103 echo Security::attr($options->end());
104 ?>"
105 data-report-group-value="<?php
106 echo Security::attr($table->group()->id());
107 ?>"
108 data-report-filters-value="<?php
109 echo \esc_attr(Security::json_encode($options->raw_filters()));
110 ?>"
111 data-report-filter-logic-value="<?php
112 echo Security::attr($options->filter_logic());
113 ?>"
114 data-report-chart-interval-value="<?php
115 echo Security::attr($options->chart_interval()->id());
116 ?>"
117 data-report-sort-column-value="<?php
118 echo Security::attr($sort_configuration->column());
119 ?>"
120 data-report-sort-direction-value="<?php
121 echo Security::attr($sort_configuration->direction());
122 ?>"
123 data-report-columns-value="<?php
124 echo \esc_attr(Security::json_encode($table->visible_column_ids()));
125 ?>"
126 data-report-quick-stats-value="<?php
127 echo \esc_attr(Security::json_encode($options->visible_quick_stats()));
128 ?>"
129 data-report-primary-chart-metric-id-value="<?php
130 echo \esc_attr($options->primary_chart_metric_id());
131 ?>"
132 data-report-secondary-chart-metric-id-value="<?php
133 echo \esc_attr($options->secondary_chart_metric_id());
134 ?>"
135 >
136 <div id="report-header-container" class="report-header-container">
137 <?php
138 echo $header;
139 ?>
140 <?php
141 $table->output_report_toolbar();
142 ?>
143 <div class="modal-background"></div>
144 </div>
145 <?php
146 echo $table->get_table_toolbar_markup();
147 ?>
148 <div class="user-journeys">
149 <?php
150 echo $table->get_table_markup($sort_configuration->column(), $sort_configuration->direction());
151 ?>
152 </div>
153 </div>
154 <?php
155 $this->notices();
156 }
157 private function interface(Table $table, $stats, $chart, $examiner_model = null)
158 {
159 $options = Dashboard_Options::getInstance();
160 $sort_configuration = $table->sanitize_sort_parameters($options->sort_column(), $options->sort_direction());
161 $header = \IAWPSCOPED\iawp_render('partials.report-header', ['report' => Report_Finder::new()->fetch_current_report(), 'can_edit' => Capability_Manager::can_edit()]);
162 $examiner_tabs = '';
163 if ($examiner_model) {
164 $header = Header::html($table, $examiner_model);
165 $available_tabs = Collection::make($this->examiner_tabs())->filter(function (array $table) use($examiner_model) {
166 return $table['table_type'] !== $examiner_model->table_type();
167 })->values()->all();
168 $current = Arr::first($available_tabs);
169 $examiner_tabs = \IAWPSCOPED\iawp_render('examiner.table-tabs', ['tables' => $available_tabs, 'active' => $current['table_type']]);
170 $table_class = Env::get_table($current['table_type']);
171 $table = new $table_class();
172 }
173 ?>
174 <div data-controller="report"
175 data-report-is-examiner-value="<?php
176 echo $options->is_examiner() ? '1' : '0';
177 ?>"
178 data-report-name-value="<?php
179 echo Security::string($options->report_name());
180 ?>"
181 data-report-report-name-value="<?php
182 echo Security::string($table->group()->singular());
183 ?>"
184 data-report-relative-range-id-value="<?php
185 echo Security::attr($options->relative_range_id());
186 ?>"
187 data-report-exact-start-value="<?php
188 echo Security::attr($options->start());
189 ?>"
190 data-report-exact-end-value="<?php
191 echo Security::attr($options->end());
192 ?>"
193 data-report-group-value="<?php
194 echo Security::attr($table->group()->id());
195 ?>"
196 data-report-filters-value="<?php
197 echo \esc_attr(Security::json_encode($options->raw_filters()));
198 ?>"
199 data-report-filter-logic-value="<?php
200 echo Security::attr($options->filter_logic());
201 ?>"
202 data-report-chart-interval-value="<?php
203 echo Security::attr($options->chart_interval()->id());
204 ?>"
205 data-report-sort-column-value="<?php
206 echo Security::attr($sort_configuration->column());
207 ?>"
208 data-report-sort-direction-value="<?php
209 echo Security::attr($sort_configuration->direction());
210 ?>"
211 data-report-columns-value="<?php
212 echo \esc_attr(Security::json_encode($table->visible_column_ids()));
213 ?>"
214 data-report-quick-stats-value="<?php
215 echo \esc_attr(Security::json_encode($options->visible_quick_stats()));
216 ?>"
217 data-report-primary-chart-metric-id-value="<?php
218 echo \esc_attr($options->primary_chart_metric_id());
219 ?>"
220 data-report-secondary-chart-metric-id-value="<?php
221 echo \esc_attr($options->secondary_chart_metric_id());
222 ?>"
223 >
224 <div id="report-header-container" class="report-header-container">
225 <?php
226 echo $header;
227 ?>
228 <?php
229 $table->output_report_toolbar();
230 ?>
231 <div class="modal-background"></div>
232 </div>
233 <?php
234 echo $stats->get_html();
235 ?>
236 <?php
237 echo $chart->get_html();
238 ?>
239 <?php
240 echo $examiner_tabs;
241 ?>
242 <?php
243 echo $table->get_table_toolbar_markup();
244 ?>
245 <?php
246 echo $table->get_table_markup($sort_configuration->column(), $sort_configuration->direction());
247 ?>
248 </div>
249 <?php
250 if (!$options->is_examiner()) {
251 ?>
252 <div id="iawp-examiner-modal" aria-hidden="true" class="mm micromodal-slide" data-controller="examiner">
253 <div tabindex="-1" class="mm__overlay mm__overlay--full-screen" data-action="click->examiner#close:self" >
254 <div role="dialog" aria-modal="true" class="mm__container examiner examiner--loading">
255 <div data-examiner-target="content" class="examiner-content"></div>
256 <?php
257 echo \IAWPSCOPED\iawp_render('examiner.skeleton');
258 ?>
259 </div>
260 </div>
261 </div>
262 <?php
263 }
264 ?>
265 <?php
266 if (!\IAWPSCOPED\iawp_is_pro()) {
267 $type = $table->group()->id();
268 if ($type == 'referrer_type') {
269 $type = 'referrer';
270 } elseif ($type == 'country' || $type == 'city') {
271 $type = 'geolocation';
272 } elseif ($type == 'device_type' || $type == 'browser' || $type == 'os') {
273 $type = 'device';
274 }
275 $report_names = ['page' => \esc_html__('Pages', 'independent-analytics'), 'referrer' => \esc_html__('Referrers', 'independent-analytics'), 'geolocation' => \esc_html__('Geolocations', 'independent-analytics'), 'device' => \esc_html__('Devices', 'independent-analytics'), 'campaigns' => \esc_html__('UTM campaigns', 'independent-analytics'), 'clicks' => \esc_html__('Clicks', 'independent-analytics'), 'ecommerce' => \esc_html__('eCommerce orders', 'independent-analytics'), 'forms' => \esc_html__('Form submissions', 'independent-analytics')];
276 ?>
277 <div id="iawp-solo-report-upsell-modal" aria-hidden="true" class="mm micromodal-slide" data-controller="examiner">
278 <div tabindex="-1" class="mm__overlay mm__overlay--full-screen" data-action="click->examiner#closeUpsell:self" >
279 <div role="dialog" aria-modal="true" class="mm__container solo-report-upsell-container">
280 <div class="title-large"><?php
281 \esc_html_e('Upgrade to Pro to Unlock Solo Reports', 'independent-analytics');
282 ?></div>
283 <div>
284 <p><?php
285 \printf(\esc_html_x('Open a full report for this %s to see its metrics, chart, and segmented data from other reports:', 'page, referrer, geolocation, or device', 'independent-analytics'), $type);
286 ?></p>
287 <ul>
288 <?php
289 foreach ($report_names as $id => $label) {
290 if ($type != $id) {
291 echo '<li>' . $label . '</li>';
292 }
293 }
294 ?>
295 </ul>
296 <a class="iawp-button purple" href="https://independentwp.com/features/solo-reports/?utm_source=User+Dashboard&utm_medium=WP+Admin&utm_campaign=Solo+Reports+modal&utm_content=Modal" target="_blank">
297 <?php
298 \esc_html_e('Learn more about Solo Reports', 'independent-analytics');
299 ?> &rarr;
300 </a>
301 </div>
302 </div>
303 </div>
304 </div>
305 <?php
306 }
307 ?>
308 <?php
309 if (Env::get_tab() === 'geo') {
310 echo '<div class="geo-ip-attribution">';
311 echo \esc_html_x('Geolocation data powered by', 'Following text is a noun: DB-IP', 'independent-analytics') . ' ' . '<a href="https://db-ip.com" target="_blank">DB-IP</a>.';
312 echo '</div>';
313 }
314 $this->notices();
315 }
316 private function notices()
317 {
318 $plugin_conflict_detector = new Plugin_Conflict_Detector();
319 $requires_logged_in_tracking = $plugin_conflict_detector->plugin_requiring_logged_in_tracking();
320 $show_logged_in_tracking_notice = $requires_logged_in_tracking && !\get_option('iawp_track_authenticated_users') && !\get_option('iawp_need_clear_cache') && !\get_option('iawp_logged_in_tracking_notice');
321 ?><div class="iawp-notices"><?php
322 if (Capability_Manager::can_edit()) {
323 if ($plugin_conflict_detector->has_conflict()) {
324 echo \IAWPSCOPED\iawp_render('notices.notice', ['notice_text' => $plugin_conflict_detector->get_error(), 'button_text' => \false, 'id' => 'plugin-conflict', 'notice' => 'iawp-error', 'plugin' => $plugin_conflict_detector->get_plugin(), 'url' => 'https://independentwp.com/knowledgebase/tracking/secure-rest-api/']);
325 } elseif (\IAWPSCOPED\iawp_is_pro() && \is_plugin_active('better-wp-security/better-wp-security.php')) {
326 $settings = \get_option('itsec-storage');
327 if (\array_key_exists('system-tweaks', $settings)) {
328 if (\array_key_exists('plugins_php', $settings['system-tweaks'])) {
329 if ($settings['system-tweaks']['plugins_php']) {
330 echo \IAWPSCOPED\iawp_render('notices.notice', ['notice_text' => \__('The "Solid Security" plugin is disabling PHP execution in the plugins folder, and this is preventing click tracking from working. Please visit the Security > Settings page, click on the Advanced section, click on System Tweaks Settings, uncheck the "Disable PHP Plugins" option, and then save.', 'independent-analytics'), 'button_text' => \false, 'id' => 'plugin-conflict', 'notice' => 'iawp-error', 'url' => 'https://independentwp.com/knowledgebase/click-tracking/allow-php-execution-plugins-folder/']);
331 }
332 }
333 }
334 }
335 if (\get_option('iawp_need_clear_cache')) {
336 echo \IAWPSCOPED\iawp_render('notices.notice', ['notice_text' => \__('Please clear your cache to ensure tracking works properly.', 'independent-analytics'), 'button_text' => \__('I\'ve cleared the cache', 'independent-analytics'), 'id' => 'iawp_need_clear_cache', 'notice' => 'iawp-warning', 'url' => 'https://independentwp.com/knowledgebase/common-questions/why-clear-cache/']);
337 }
338 if ($show_logged_in_tracking_notice) {
339 echo \IAWPSCOPED\iawp_render('notices.notice', ['notice_text' => '<strong>' . \sprintf(\_x('%s compatibility:', 'Variable is the name of a plugin', 'independent-analytics'), $requires_logged_in_tracking) . '</strong> ' . \__('We recommend you enable tracking for logged-in visitors.', 'independent-analytics'), 'button_text' => \__('Dismiss', 'independent-analytics'), 'id' => 'enable-logged-in-tracking', 'notice' => 'iawp-warning', 'url' => 'https://independentwp.com/knowledgebase/tracking/how-to-track-logged-in-visitors/']);
340 }
341 if (\IAWPSCOPED\iawp_db_version() > 0 && !Database::has_correct_database_privileges()) {
342 echo \IAWPSCOPED\iawp_render('notices.notice', ['notice_text' => \__('Your site is missing the following critical database permissions:', 'independent-analytics') . ' ' . \implode(', ', Database::missing_database_privileges()) . '. ' . \__('There is no issue at this time, but you will need to enable the missing permissions before updating the plugin to a newer version to ensure an error is avoided. Please click this link to read our tutorial:', 'independent-analytics'), 'button_text' => \false, 'id' => 'missing-permissions', 'notice' => 'iawp-error', 'url' => 'https://independentwp.com/knowledgebase/common-questions/missing-database-permissions/']);
343 }
344 if (Env::get_tab() === 'clicks') {
345 if (!\get_option('iawp_clicks_sync_notice')) {
346 echo \IAWPSCOPED\iawp_render('notices.notice', ['notice_text' => \__('Click data syncs every 60 seconds. Please allow for this delay when testing clicks on new links.', 'independent-analytics'), 'button_text' => \__('Dismiss', 'independent-analytics'), 'id' => 'iawp_clicks_sync_notice', 'notice' => 'iawp-warning', 'url' => 'https://independentwp.com/knowledgebase/click-tracking/click-tracking-update-process/']);
347 }
348 }
349 }
350 ?>
351 </div><?php
352 if (\get_option('iawp_show_gsg') === '1' && !\get_option('iawp_need_clear_cache') && !$show_logged_in_tracking_notice && !$plugin_conflict_detector->has_conflict() && (Env::get_tab() !== 'clicks' || Env::get_tab() === 'clicks' && \get_option('iawp_clicks_sync_notice')) && Capability_Manager::show_branded_ui()) {
353 echo \IAWPSCOPED\iawp_render('notices.getting-started');
354 }
355 }
356 private function examiner_tabs() : array
357 {
358 return [['table_type' => 'views', 'name' => \__('Pages', 'independent-analytics')], ['table_type' => 'referrers', 'name' => \__('Referrers', 'independent-analytics')], ['table_type' => 'geo', 'name' => \__('Geographic', 'independent-analytics')], ['table_type' => 'devices', 'name' => \__('Devices', 'independent-analytics')], ['table_type' => 'campaigns', 'name' => \__('Campaigns', 'independent-analytics')], ['table_type' => 'clicks', 'name' => \__('Clicks', 'independent-analytics')]];
359 }
360 }
361