PluginProbe
Analytify – Google Analytics Dashboard For WordPress (GA4 analytics tracking) / trunk
Analytify – Google Analytics Dashboard For WordPress (GA4 analytics tracking) vtrunk
9.1.2 9.1.1 9.1.0 9.0.2 9.0.1 trunk 1.0.0 1.0.1 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.0.7 1.1.0 1.1.1 1.2.0 1.2.1 1.2.2 1.2.3 1.2.4 1.2.5 1.3.0 1.3.1 1.3.2 All 153 releases
wp-analytify / classes / analytify-rest / endpoints-general.php

endpoints-general.php in Analytify – Google Analytics Dashboard For WordPress (GA4 analytics tracking) trunk, at classes/analytify-rest/endpoints-general.php

435 lines 15.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Analytify REST Endpoints General Trait
4 *
5 * This trait provides general analytics endpoints for the Analytify REST API.
6 * It was created to separate general analytics functionality from the main REST class,
7 * offering endpoints for common analytics reports like general stats, top pages,
8 * geographic data, and system information.
9 *
10 * PURPOSE:
11 * - Provides general analytics endpoints
12 * - Handles common analytics data requests
13 * - Manages general statistics processing
14 * - Offers geographic and system analytics
15 *
16 * @package WP_Analytify
17 * @subpackage REST_API
18 * @since 8.0.0
19 */
20
21 if ( ! defined( 'ABSPATH' ) ) {
22 exit; }
23
24 trait Analytify_Rest_Endpoints_General {
25
26 /**
27 * Get general analytics statistics
28 *
29 * Retrieves and formats general analytics data including pageviews,
30 * sessions, users, and other key metrics for the specified date range.
31 * Sets up comparison dates and defines box descriptions for the dashboard.
32 *
33 * @return array<string, mixed> General analytics statistics with box and chart data
34 */
35 private function general_stats() {
36 $this->set_compare_dates();
37 $boxes_description = array(
38 'sessions' => array(
39 'title' => esc_html__( 'Sessions', 'wp-analytify' ),
40 'description' => esc_html__( 'A session is a time period in which a user is actively engaged with your website.', 'wp-analytify' ),
41 'bottom' => false,
42 'number' => 0,
43 ),
44 'visitors' => array(
45 'title' => esc_html__( 'Visitors', 'wp-analytify' ),
46 'description' => esc_html__( 'Users who complete a minimum of one session on your website.', 'wp-analytify' ),
47 'bottom' => false,
48 'number' => 0,
49 ),
50 'pageviews' => array(
51 'title' => esc_html__( 'Page Views', 'wp-analytify' ),
52 'description' => esc_html__( 'Page Views are the total number of Pageviews, these include repeated views.', 'wp-analytify' ),
53 'bottom' => false,
54 'number' => 0,
55 ),
56 'avg_time_on_site' => array(
57 'title' => esc_html__( 'Avg. Time on Site', 'wp-analytify' ),
58 'description' => esc_html__( 'Total time that a single user spends on your website.', 'wp-analytify' ),
59 'bottom' => false,
60 'number' => 0,
61 ),
62 'bounce_rate' => array(
63 'title' => esc_html__( 'Bounce Rate', 'wp-analytify' ),
64 'description' => esc_html__( 'Percentage of single page visits (i.e number of visits in which a visitor leaves your website from the landing page without browsing your website).', 'wp-analytify' ),
65 'append' => '<span class="analytify_xl_f">%</span>',
66 'bottom' => false,
67 'number' => 0,
68 ),
69 'pages_session' => array(
70 'title' => esc_html__( 'Pages per Session', 'wp-analytify' ),
71 'description' => esc_html__( 'Pages per Session is the number of pages viewed by a user during a single session. Repeated views are counted.', 'wp-analytify' ),
72 'bottom' => false,
73 'number' => 0,
74 ),
75 'new_sessions' => array(
76 'title' => esc_html__( '% New Sessions', 'wp-analytify' ),
77 'description' => esc_html__( 'A new session is when a new user comes to your website.', 'wp-analytify' ),
78 'append' => '<span class="analytify_xl_f">%</span>',
79 'bottom' => false,
80 'number' => 0,
81 ),
82 'engaged_sessions' => array(
83 'title' => esc_html__( 'Engaged Sessions', 'wp-analytify' ),
84 'description' => esc_html__( 'The number of sessions that lasted longer than 10 seconds, or had a conversion event, or had 2 or more page views.', 'wp-analytify' ),
85 'bottom' => false,
86 'number' => 0,
87 ),
88 );
89
90 unset( $boxes_description['new_sessions'] );
91
92 // Fetch main GA4 general stats data with newVsReturning dimension.
93 $general_stats_raw = $this->wp_analytify->get_reports(
94 'show-default-overall-dashboard',
95 array(
96 'sessions',
97 'totalUsers',
98 'screenPageViews',
99 'averageSessionDuration',
100 'bounceRate',
101 'screenPageViewsPerSession',
102 'engagedSessions',
103 'userEngagementDuration',
104 'activeUsers',
105 ),
106 $this->get_dates(),
107 array(
108 'newVsReturning',
109 )
110 );
111
112 // Device category stats.
113 $device_category_stats = $this->wp_analytify->get_reports(
114 'show-default-overall-device-dashboard',
115 array( 'sessions' ),
116 $this->get_dates(),
117 array( 'deviceCategory' ),
118 array(
119 'type' => 'dimension',
120 'name' => 'deviceCategory',
121 )
122 );
123
124 // Browser breakdown stats.
125 $browser_stats_raw = $this->wp_analytify->get_reports(
126 'show-default-browser-breakdown-dashboard',
127 array( 'sessions' ),
128 $this->get_dates(),
129 array( 'browser' ),
130 array(
131 'type' => 'metric',
132 'name' => 'sessions',
133 'order' => 'desc',
134 ),
135 array(
136 'logic' => 'AND',
137 'filters' => array(
138 array(
139 'type' => 'dimension',
140 'name' => 'browser',
141 'match_type' => 4,
142 'value' => '(not set)',
143 'not_expression' => true,
144 ),
145 ),
146 ),
147 3
148 );
149
150 $general_stats = isset( $general_stats_raw['aggregations'] ) ? $general_stats_raw['aggregations'] : array();
151
152 // Build boxes (main stats).
153 $boxes_stats = array(
154 'sessions' => array(
155 'raw' => $general_stats['sessions'] ?? 0,
156 'number' => WPANALYTIFY_Utils::pretty_numbers( $general_stats['sessions'] ?? 0 ),
157 ),
158 'visitors' => array(
159 'raw' => $general_stats['totalUsers'] ?? 0,
160 'number' => WPANALYTIFY_Utils::pretty_numbers( $general_stats['totalUsers'] ?? 0 ),
161 ),
162 'pageviews' => array(
163 'raw' => $general_stats['screenPageViews'] ?? 0,
164 'number' => WPANALYTIFY_Utils::pretty_numbers( $general_stats['screenPageViews'] ?? 0 ),
165 ),
166 'avg_time_on_site' => array(
167 'raw' => $general_stats['averageSessionDuration'] ?? 0,
168 'number' => WPANALYTIFY_Utils::pretty_time( $general_stats['averageSessionDuration'] ?? 0 ),
169 ),
170 'bounce_rate' => array(
171 'raw' => $general_stats['bounceRate'] ?? 0,
172 'number' => WPANALYTIFY_Utils::fraction_to_percentage( $general_stats['bounceRate'] ?? 0 ),
173 ),
174 'pages_session' => array(
175 'raw' => $general_stats['screenPageViewsPerSession'] ?? 0,
176 'number' => round( $general_stats['screenPageViewsPerSession'] ?? 0, 2 ),
177 ),
178 'engaged_sessions' => array(
179 'raw' => $general_stats['engagedSessions'] ?? 0,
180 'number' => WPANALYTIFY_Utils::pretty_numbers( $general_stats['engagedSessions'] ?? 0 ),
181 ),
182 );
183
184 // NEW vs RETURNING processing.
185 $new_vs_returning_data = array(
186 'new' => array(
187 'sessions' => 0,
188 'users' => 0,
189 ),
190 'returning' => array(
191 'sessions' => 0,
192 'users' => 0,
193 ),
194 'unknown' => array(
195 'sessions' => 0,
196 'users' => 0,
197 ),
198 );
199
200 if ( isset( $general_stats_raw['rows'] ) && is_array( $general_stats_raw['rows'] ) ) {
201 foreach ( $general_stats_raw['rows'] as $row ) {
202 $type = strtolower( trim( $row['newVsReturning'] ?? '' ) );
203 if ( 'new' === $type ) {
204 $new_vs_returning_data['new']['sessions'] += (int) $row['sessions'];
205 $new_vs_returning_data['new']['users'] += (int) $row['totalUsers'];
206 } elseif ( 'returning' === $type ) {
207 $new_vs_returning_data['returning']['sessions'] += (int) $row['sessions'];
208 $new_vs_returning_data['returning']['users'] += (int) $row['totalUsers'];
209 } else {
210 $new_vs_returning_data['unknown']['sessions'] += (int) $row['sessions'];
211 $new_vs_returning_data['unknown']['users'] += (int) $row['totalUsers'];
212 }
213 }
214 }
215
216 $chart_description['new_vs_returning_visitors'] = array(
217 'title' => __( 'New vs Returning Visitors', 'wp-analytify' ),
218 'type' => 'PIE',
219 'stats' => array(
220 'new' => array(
221 'label' => __( 'New', 'wp-analytify' ),
222 'number' => $new_vs_returning_data['new']['users'],
223 'sessions' => WPANALYTIFY_Utils::pretty_numbers( $new_vs_returning_data['new']['sessions'] ),
224 ),
225 'returning' => array(
226 'label' => __( 'Returning', 'wp-analytify' ),
227 'number' => $new_vs_returning_data['returning']['users'],
228 'sessions' => WPANALYTIFY_Utils::pretty_numbers( $new_vs_returning_data['returning']['sessions'] ),
229 ),
230 ),
231 'colors' => ( function () {
232 $default_colors = array( '#03a1f8', '#00c853' );
233 $filtered_colors = apply_filters( 'analytify_new_vs_returning_visitors_chart_colors', array() );
234 return array_replace( $default_colors, $filtered_colors );
235 } )(),
236 );
237
238 // Device category stats (mobile/tablet/desktop).
239 $chart_description['visitor_devices'] = array(
240 'title' => esc_html__( 'Devices of Visitors', 'wp-analytify' ),
241 'type' => 'PIE',
242 'stats' => array(
243 'mobile' => array(
244 'label' => esc_html__( 'Mobile', 'wp-analytify' ),
245 'number' => 0,
246 ),
247 'tablet' => array(
248 'label' => esc_html__( 'Tablet', 'wp-analytify' ),
249 'number' => 0,
250 ),
251 'desktop' => array(
252 'label' => esc_html__( 'Desktop', 'wp-analytify' ),
253 'number' => 0,
254 ),
255 ),
256 'colors' => ( function () {
257 $default_colors = array( '#444444', '#ffbc00', '#ff5252' );
258 $filtered_colors = apply_filters( 'analytify_visitor_devices_chart_colors', array() );
259 return array_replace( $default_colors, $filtered_colors );
260 } )(),
261 );
262
263 if ( isset( $device_category_stats['rows'] ) && is_array( $device_category_stats['rows'] ) ) {
264 foreach ( $device_category_stats['rows'] as $device ) {
265 if ( isset( $chart_description['visitor_devices']['stats'][ $device['deviceCategory'] ] ) ) {
266 $chart_description['visitor_devices']['stats'][ $device['deviceCategory'] ]['number'] = $device['sessions'];
267 }
268 }
269 }
270
271 // Browser breakdown stats processing.
272 $browser_breakdown_stats = array();
273 $browser_colors = array( '#4285F4', '#EA4335', '#FBBC04', '#34A853', '#FF6D00', '#46BDC6', '#7B1FA2', '#E91E63', '#00897B', '#5E35B1' );
274
275 if ( isset( $browser_stats_raw['rows'] ) && is_array( $browser_stats_raw['rows'] ) ) {
276 $color_index = 0;
277 foreach ( $browser_stats_raw['rows'] as $browser ) {
278 if ( isset( $browser['browser'] ) && isset( $browser['sessions'] ) ) {
279 $browser_key = strtolower( str_replace( ' ', '_', $browser['browser'] ) );
280 $browser_breakdown_stats[ $browser_key ] = array(
281 'label' => $browser['browser'],
282 'number' => $browser['sessions'],
283 );
284 ++$color_index;
285 }
286 }
287 }
288
289 $chart_description['browser_breakdown'] = array(
290 'title' => esc_html__( 'Browser Breakdown', 'wp-analytify' ),
291 'description' => esc_html__( 'Top 3 Browsers by Sessions.', 'wp-analytify' ),
292 'type' => 'PIE',
293 'stats' => $browser_breakdown_stats,
294 'colors' => ( function () use ( $browser_colors ) {
295 $filtered_colors = apply_filters( 'analytify_browser_breakdown_chart_colors', array() );
296 return ! empty( $filtered_colors ) ? $filtered_colors : $browser_colors;
297 } )(),
298 );
299
300 // Compare stats if comparison date is set.
301 if ( $this->compare_start_date && $this->compare_end_date ) {
302 $compare_stats_raw = $this->wp_analytify->get_reports(
303 'show-default-overall-dashboard-compare',
304 array(
305 'sessions',
306 'totalUsers',
307 'screenPageViews',
308 'averageSessionDuration',
309 'bounceRate',
310 'screenPageViewsPerSession',
311 'engagedSessions',
312 ),
313 array(
314 'start' => $this->compare_start_date,
315 'end' => $this->compare_end_date,
316 )
317 );
318 }
319
320 if ( isset( $compare_stats_raw['aggregations'] ) ) {
321 $compare_stats = array(
322 'sessions' => $compare_stats_raw['aggregations']['sessions'] ?? 0,
323 'visitors' => $compare_stats_raw['aggregations']['totalUsers'] ?? 0,
324 'pageviews' => $compare_stats_raw['aggregations']['screenPageViews'] ?? 0,
325 'avg_time_on_site' => $compare_stats_raw['aggregations']['averageSessionDuration'] ?? 0,
326 'bounce_rate' => $compare_stats_raw['aggregations']['bounceRate'] ?? 0,
327 'pages_session' => $compare_stats_raw['aggregations']['screenPageViewsPerSession'] ?? 0,
328 'engaged_sessions' => $compare_stats_raw['aggregations']['engagedSessions'] ?? 0,
329 );
330 }
331
332 // Footer (optional).
333 $footer_description = false;
334 if ( isset( $general_stats['userEngagementDuration'] ) ) {
335 $footer_description = apply_filters( 'analytify_general_stats_footer', $general_stats['userEngagementDuration'], array( $this->start_date, $this->end_date ) );
336 }
337
338 // Fill final box values and compare deltas.
339 foreach ( $boxes_description as $key => $box ) {
340 if ( isset( $boxes_stats[ $key ] ) ) {
341 $boxes_description[ $key ]['number'] = (string) $boxes_stats[ $key ]['number'];
342 if ( isset( $compare_stats[ $key ] ) ) {
343 $boxes_description[ $key ]['bottom'] = $this->compare_stat( $boxes_stats[ $key ]['raw'], $compare_stats[ $key ], $key );
344 }
345 }
346 }
347
348 return array(
349 'success' => true,
350 'boxes' => apply_filters( 'analytify_general_stats_boxes', $boxes_description, array( $this->start_date, $this->end_date ) ),
351 'charts' => apply_filters( 'analytify_general_stats_charts', $chart_description, array( $this->start_date, $this->end_date ) ),
352 'footer' => $footer_description,
353 );
354 }
355
356 /**
357 * Get general stats footer.
358 *
359 * @param mixed $number The number value.
360 * @param mixed $data The data parameter (unused).
361 * @return string
362 */
363 public function general_stats_footer( $number, $data ) { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundAfterLastUsed -- Parameter required by filter
364 // translators: %s is the formatted time duration.
365 return sprintf( __( 'Total time visitors spent on your site: %s.', 'wp-analytify' ), '<span class="analytify_red general_stats_message">' . WPANALYTIFY_Utils::pretty_time( $number ) . '</span>' );
366 }
367
368 /**
369 * Get profile info.
370 *
371 * @param string $key The key to get.
372 * @return mixed
373 */
374 private function get_profile_info( $key ) {
375 $dashboard_profile_id = $this->wp_analytify->settings->get_option( 'profile_for_dashboard', 'wp-analytify-profile' );
376 switch ( $key ) {
377 case 'profile_id':
378 return $dashboard_profile_id;
379 case 'website_url':
380 return WP_ANALYTIFY_FUNCTIONS::search_profile_info( $dashboard_profile_id, 'websiteUrl' );
381 default:
382 return null;
383 }
384 }
385
386 /**
387 * Set compare dates.
388 *
389 * @return void
390 */
391 private function set_compare_dates() {
392 $date_diff = WPANALYTIFY_Utils::calculate_date_diff( $this->start_date, $this->end_date );
393 if ( ! $date_diff ) {
394 return; }
395 $this->compare_start_date = $date_diff['start_date'];
396 $this->compare_end_date = $date_diff['end_date'];
397 $this->compare_days = $date_diff['diff_days'];
398 }
399
400 /**
401 * Compare stat.
402 *
403 * @param mixed $current_stat The current stat.
404 * @param mixed $old_stat The old stat.
405 * @param string $type The type.
406 * @return array|false
407 */
408 private function compare_stat( $current_stat, $old_stat, $type ) {
409 if ( is_null( $this->compare_start_date ) || is_null( $this->compare_end_date ) || is_null( $this->compare_days ) ) {
410 return false; }
411 if ( ! $old_stat || 0 === $old_stat ) {
412 return false; }
413 $number = number_format( ( ( $current_stat - $old_stat ) / $old_stat ) * 100, 2 );
414 $arrow_type = ( 'bounce_rate' === $type ) ? ( $number < 0 ? 'analytify_green_inverted' : 'analytify_red_inverted' ) : ( $number > 0 ? 'analytify_green' : 'analytify_red' );
415 return array(
416 'arrow_type' => $arrow_type,
417 'main_text' => $number . esc_html__( '%', 'wp-analytify' ),
418 // translators: %s is the number of days.
419 'sub_text' => sprintf( esc_html__( '%s days ago', 'wp-analytify' ), $this->compare_days ),
420 );
421 }
422
423 /**
424 * Get dates.
425 *
426 * @return array
427 */
428 private function get_dates() {
429 return array(
430 'start' => $this->start_date,
431 'end' => $this->end_date,
432 );
433 }
434 }
435