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 | ?> → |
| 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 |