prefix . 'accessiq_sessions'; $accessiq_clicks_tbl = $wpdb->prefix . 'accessiq_clicks'; $accessiq_cutoff = gmdate( 'Y-m-d H:i:s', strtotime( '-' . $accessiq_days . ' days', current_time( 'timestamp' ) ) ); // ── Top pages ────────────────────────────────────────────────────────────── // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching $accessiq_top_pages = $wpdb->get_results( $wpdb->prepare( 'SELECT t.page_url, COUNT(*) AS sessions, AVG(t.time_spent) AS avg_duration, SUM(CASE WHEN t.is_bounce = 1 THEN 1 ELSE 0 END) AS bounces, (SELECT s2.device_type FROM `' . esc_sql( $accessiq_sessions_tbl ) . '` s2 WHERE s2.page_url = t.page_url AND s2.created_at >= %s GROUP BY s2.device_type ORDER BY COUNT(*) DESC LIMIT 1) AS device_type FROM `' . esc_sql( $accessiq_sessions_tbl ) . '` t WHERE t.created_at >= %s AND t.page_url IS NOT NULL AND TRIM(t.page_url) != \'\' GROUP BY t.page_url ORDER BY sessions DESC LIMIT 10', $accessiq_cutoff, $accessiq_cutoff ) ); // ── KPI: Total sessions ──────────────────────────────────────────────────── // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching $accessiq_stat_total_sessions = (int) $wpdb->get_var( $wpdb->prepare( 'SELECT COUNT(*) FROM `' . esc_sql( $accessiq_sessions_tbl ) . '` WHERE created_at >= %s', $accessiq_cutoff ) ); // ── KPI: Avg time ────────────────────────────────────────────────────────── // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching $accessiq_stat_avg_time_raw = $wpdb->get_var( $wpdb->prepare( 'SELECT AVG(time_spent) FROM `' . esc_sql( $accessiq_sessions_tbl ) . '` WHERE created_at >= %s AND time_spent < 3600', $accessiq_cutoff ) ); $accessiq_stat_avg_time_secs = $accessiq_stat_avg_time_raw ? (int) round( (float) $accessiq_stat_avg_time_raw ) : 0; $accessiq_stat_avg_time = $accessiq_stat_avg_time_secs >= 60 ? ( floor( $accessiq_stat_avg_time_secs / 60 ) . 'm ' . ( $accessiq_stat_avg_time_secs % 60 ) . 's' ) : ( $accessiq_stat_avg_time_secs . 's' ); // ── KPI: Bounce rate ─────────────────────────────────────────────────────── // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching $accessiq_stat_bounces = (int) $wpdb->get_var( $wpdb->prepare( 'SELECT COUNT(*) FROM `' . esc_sql( $accessiq_sessions_tbl ) . '` WHERE created_at >= %s AND is_bounce = 1', $accessiq_cutoff ) ); $accessiq_stat_bounce_rate = $accessiq_stat_total_sessions > 0 ? round( ( $accessiq_stat_bounces / $accessiq_stat_total_sessions ) * 100 ) : 0; $accessiq_br_cls = $accessiq_stat_bounce_rate > 70 ? 'aiq-ba-val--red' : ( $accessiq_stat_bounce_rate >= 40 ? 'aiq-ba-val--amber' : 'aiq-ba-val--green' ); $accessiq_br_hint = $accessiq_stat_bounce_rate > 70 ? __( 'High — review content', 'accessiq' ) : ( $accessiq_stat_bounce_rate >= 40 ? __( 'Average range', 'accessiq' ) : __( 'Excellent engagement', 'accessiq' ) ); // ── KPI: Top device (kept for JS compat, moved to hidden) ───────────────── // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching $accessiq_stat_top_device = $wpdb->get_var( $wpdb->prepare( 'SELECT device_type FROM `' . esc_sql( $accessiq_sessions_tbl ) . '` WHERE created_at >= %s GROUP BY device_type ORDER BY COUNT(*) DESC LIMIT 1', $accessiq_cutoff ) ); $accessiq_stat_top_device = $accessiq_stat_top_device ? $accessiq_stat_top_device : '—'; // ── KPI: Total clicks ───────────────────────────────────────────────────── // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching $accessiq_stat_total_clicks = (int) $wpdb->get_var( $wpdb->prepare( 'SELECT COUNT(*) FROM `' . esc_sql( $accessiq_clicks_tbl ) . '` WHERE created_at >= %s', $accessiq_cutoff ) ); $accessiq_current_days = $accessiq_days; // ── Data retention ──────────────────────────────────────────────────────── $accessiq_retention_days = absint( get_option( 'accessiq_analytics_data_retention', 90 ) ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.NotPrepared $accessiq_oldest_raw = $wpdb->get_var( 'SELECT MIN(created_at) FROM `' . esc_sql( $accessiq_sessions_tbl ) . '`' ); $accessiq_days_stored = $accessiq_oldest_raw ? (int) ceil( ( time() - strtotime( $accessiq_oldest_raw ) ) / DAY_IN_SECONDS ) : 0; $accessiq_retention_pct = $accessiq_retention_days > 0 ? min( 100, (int) round( ( $accessiq_days_stored / $accessiq_retention_days ) * 100 ) ) : 0; // ── Sparklines: last 7-day session counts ───────────────────────────────── $accessiq_spark_cutoff = gmdate( 'Y-m-d H:i:s', strtotime( '-7 days', current_time( 'timestamp' ) ) ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching $accessiq_spark_raw = $wpdb->get_results( $wpdb->prepare( // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared 'SELECT DATE(created_at) AS day, COUNT(*) AS cnt FROM `' . esc_sql( $accessiq_sessions_tbl ) . '` WHERE created_at >= %s GROUP BY DATE(created_at) ORDER BY day ASC', $accessiq_spark_cutoff ) ); $accessiq_spark_map = array(); foreach ( (array) $accessiq_spark_raw as $accessiq_spark_row ) { $accessiq_spark_map[ $accessiq_spark_row->day ] = (int) $accessiq_spark_row->cnt; } $accessiq_spark_vals = array(); for ( $accessiq_si = 6; $accessiq_si >= 0; $accessiq_si-- ) { $accessiq_spark_vals[] = isset( $accessiq_spark_map[ gmdate( 'Y-m-d', strtotime( '-' . $accessiq_si . ' days' ) ) ] ) ? (int) $accessiq_spark_map[ gmdate( 'Y-m-d', strtotime( '-' . $accessiq_si . ' days' ) ) ] : 0; } $accessiq_spark_max = max( array_merge( array( 1 ), $accessiq_spark_vals ) ); // ── Export nonce ────────────────────────────────────────────────────────── $accessiq_export_nonce = wp_create_nonce( 'accessiq_export_nonce' ); ?>
| sessions; ?> |
%
|
|||