init_consent_analytics();
}
/**
* Initialize consent analytics
*/
private function init_consent_analytics() {
// Hook into consent events
add_action('tigerstyle_whiskers_consent_granted', array($this, 'track_consent_event'));
add_action('tigerstyle_whiskers_consent_withdrawn', array($this, 'track_consent_withdrawal'));
add_action('tigerstyle_whiskers_consent_updated', array($this, 'track_consent_update'));
// Admin hooks for dashboard
if (is_admin()) {
add_action('wp_ajax_tigerstyle_whiskers_get_analytics_data', array($this, 'ajax_get_analytics_data'));
add_action('wp_ajax_tigerstyle_whiskers_export_analytics', array($this, 'ajax_export_analytics'));
}
// Daily aggregation
add_action('tigerstyle_whiskers_daily_analytics_aggregation', array($this, 'aggregate_daily_stats'));
if (!wp_next_scheduled('tigerstyle_whiskers_daily_analytics_aggregation')) {
wp_schedule_event(time(), 'daily', 'tigerstyle_whiskers_daily_analytics_aggregation');
}
// Frontend tracking (only with consent)
add_action('wp_footer', array($this, 'inject_analytics_tracking'));
if (defined('WP_DEBUG') && WP_DEBUG) {
error_log('TigerStyle Whiskers: Consent analytics whisker is observing patterns with feline intelligence!');
}
}
/**
* Track consent event
*/
public function track_consent_event($consent_data) {
if (!$this->analytics_enabled) {
return;
}
$event_data = array(
'event_type' => 'consent_granted',
'timestamp' => current_time('timestamp'),
'consent_categories' => $consent_data,
'user_agent_hash' => hash('sha256', $_SERVER['HTTP_USER_AGENT'] ?? ''),
'ip_hash' => hash('sha256', $this->get_visitor_ip()),
'session_id' => $this->get_session_id(),
'geo_data' => $this->get_geo_context(),
'referrer_hash' => hash('sha256', $_SERVER['HTTP_REFERER'] ?? ''),
'page_url_hash' => hash('sha256', $_SERVER['REQUEST_URI'] ?? '')
);
$this->store_analytics_event($event_data);
$this->update_real_time_stats($event_data);
}
/**
* Track consent withdrawal
*/
public function track_consent_withdrawal($withdrawal_data) {
if (!$this->analytics_enabled) {
return;
}
$event_data = array(
'event_type' => 'consent_withdrawn',
'timestamp' => current_time('timestamp'),
'withdrawn_categories' => $withdrawal_data['categories'] ?? array(),
'reason' => $withdrawal_data['reason'] ?? '',
'session_id' => $this->get_session_id(),
'geo_data' => $this->get_geo_context()
);
$this->store_analytics_event($event_data);
$this->update_real_time_stats($event_data);
}
/**
* Store analytics event in database
*/
private function store_analytics_event($event_data) {
global $wpdb;
$table_name = $wpdb->prefix . 'tigerstyle_whiskers_consent_analytics';
// Create table if it doesn't exist
$this->create_analytics_table();
$wpdb->insert(
$table_name,
array(
'event_type' => $event_data['event_type'],
'event_data' => json_encode($event_data),
'timestamp' => date('Y-m-d H:i:s', $event_data['timestamp']),
'date_created' => date('Y-m-d', $event_data['timestamp']),
'hour_created' => date('H', $event_data['timestamp']),
'country_code' => $event_data['geo_data']['country_code'] ?? 'UNKNOWN',
'session_id_hash' => hash('sha256', $event_data['session_id'] ?? '')
),
array('%s', '%s', '%s', '%s', '%s', '%s', '%s')
);
}
/**
* Create analytics table
*/
private function create_analytics_table() {
global $wpdb;
$table_name = $wpdb->prefix . 'tigerstyle_whiskers_consent_analytics';
$charset_collate = $wpdb->get_charset_collate();
$sql = "CREATE TABLE IF NOT EXISTS $table_name (
id bigint(20) NOT NULL AUTO_INCREMENT,
event_type varchar(50) NOT NULL,
event_data longtext NOT NULL,
timestamp datetime NOT NULL,
date_created date NOT NULL,
hour_created tinyint(2) NOT NULL,
country_code varchar(2) NOT NULL,
session_id_hash varchar(64) NOT NULL,
PRIMARY KEY (id),
KEY event_type (event_type),
KEY date_created (date_created),
KEY hour_created (hour_created),
KEY country_code (country_code),
KEY timestamp (timestamp)
) $charset_collate;";
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
dbDelta($sql);
// Create daily aggregation table
$aggregation_table = $wpdb->prefix . 'tigerstyle_whiskers_consent_analytics_daily';
$sql_agg = "CREATE TABLE IF NOT EXISTS $aggregation_table (
id bigint(20) NOT NULL AUTO_INCREMENT,
date_aggregated date NOT NULL,
total_consent_requests bigint(20) DEFAULT 0,
total_consent_granted bigint(20) DEFAULT 0,
total_consent_denied bigint(20) DEFAULT 0,
analytics_consent_rate decimal(5,2) DEFAULT 0,
marketing_consent_rate decimal(5,2) DEFAULT 0,
preferences_consent_rate decimal(5,2) DEFAULT 0,
top_countries text,
hourly_distribution text,
consent_categories_breakdown text,
created_at timestamp DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id),
UNIQUE KEY date_aggregated (date_aggregated)
) $charset_collate;";
dbDelta($sql_agg);
}
/**
* Update real-time statistics
*/
private function update_real_time_stats($event_data) {
$stats_key = 'tigerstyle_whiskers_realtime_stats';
$current_stats = get_option($stats_key, array(
'today_total' => 0,
'today_accepted' => 0,
'today_denied' => 0,
'last_updated' => time(),
'hourly_breakdown' => array_fill(0, 24, 0)
));
$current_hour = date('H', $event_data['timestamp']);
if ($event_data['event_type'] === 'consent_granted') {
$current_stats['today_total']++;
$current_stats['today_accepted']++;
$current_stats['hourly_breakdown'][$current_hour]++;
} elseif ($event_data['event_type'] === 'consent_denied') {
$current_stats['today_total']++;
$current_stats['today_denied']++;
$current_stats['hourly_breakdown'][$current_hour]++;
}
$current_stats['last_updated'] = time();
update_option($stats_key, $current_stats);
}
/**
* Get analytics dashboard data
*/
public function get_dashboard_data($date_range = '30_days') {
$cache_key = 'tigerstyle_whiskers_dashboard_' . $date_range;
$cached_data = get_transient($cache_key);
if ($cached_data !== false) {
return $cached_data;
}
global $wpdb;
$analytics_table = $wpdb->prefix . 'tigerstyle_whiskers_consent_analytics';
$aggregation_table = $wpdb->prefix . 'tigerstyle_whiskers_consent_analytics_daily';
// Calculate date range
$end_date = current_time('Y-m-d');
$start_date = date('Y-m-d', strtotime("-{$date_range}", strtotime($end_date)));
$dashboard_data = array(
'overview' => $this->get_overview_stats($start_date, $end_date),
'consent_trends' => $this->get_consent_trends($start_date, $end_date),
'geographic_distribution' => $this->get_geographic_distribution($start_date, $end_date),
'category_preferences' => $this->get_category_preferences($start_date, $end_date),
'hourly_patterns' => $this->get_hourly_patterns($start_date, $end_date),
'device_analysis' => $this->get_device_analysis($start_date, $end_date),
'compliance_insights' => $this->get_compliance_insights($start_date, $end_date),
'performance_metrics' => $this->get_performance_metrics($start_date, $end_date)
);
// Cache for 1 hour
set_transient($cache_key, $dashboard_data, 3600);
return $dashboard_data;
}
/**
* Get overview statistics
*/
private function get_overview_stats($start_date, $end_date) {
global $wpdb;
$table_name = $wpdb->prefix . 'tigerstyle_whiskers_consent_analytics';
$total_events = $wpdb->get_var($wpdb->prepare(
"SELECT COUNT(*) FROM {$table_name} WHERE date_created BETWEEN %s AND %s",
$start_date, $end_date
));
$consent_granted = $wpdb->get_var($wpdb->prepare(
"SELECT COUNT(*) FROM {$table_name} WHERE event_type = 'consent_granted' AND date_created BETWEEN %s AND %s",
$start_date, $end_date
));
$consent_denied = $wpdb->get_var($wpdb->prepare(
"SELECT COUNT(*) FROM {$table_name} WHERE event_type = 'consent_denied' AND date_created BETWEEN %s AND %s",
$start_date, $end_date
));
$unique_sessions = $wpdb->get_var($wpdb->prepare(
"SELECT COUNT(DISTINCT session_id_hash) FROM {$table_name} WHERE date_created BETWEEN %s AND %s",
$start_date, $end_date
));
$acceptance_rate = $total_events > 0 ? round(($consent_granted / $total_events) * 100, 2) : 0;
return array(
'total_consent_requests' => intval($total_events),
'total_accepted' => intval($consent_granted),
'total_denied' => intval($consent_denied),
'unique_visitors' => intval($unique_sessions),
'acceptance_rate' => $acceptance_rate,
'avg_daily_requests' => $this->calculate_avg_daily_requests($total_events, $start_date, $end_date)
);
}
/**
* Get consent trends over time
*/
private function get_consent_trends($start_date, $end_date) {
global $wpdb;
$table_name = $wpdb->prefix . 'tigerstyle_whiskers_consent_analytics';
$trends = $wpdb->get_results($wpdb->prepare(
"SELECT
date_created,
COUNT(*) as total_requests,
SUM(CASE WHEN event_type = 'consent_granted' THEN 1 ELSE 0 END) as accepted,
SUM(CASE WHEN event_type = 'consent_denied' THEN 1 ELSE 0 END) as denied
FROM {$table_name}
WHERE date_created BETWEEN %s AND %s
GROUP BY date_created
ORDER BY date_created ASC",
$start_date, $end_date
), ARRAY_A);
// Fill in missing dates with zero values
$filled_trends = $this->fill_missing_dates($trends, $start_date, $end_date);
return array(
'daily_trends' => $filled_trends,
'trend_analysis' => $this->analyze_trends($filled_trends)
);
}
/**
* Get geographic distribution
*/
private function get_geographic_distribution($start_date, $end_date) {
global $wpdb;
$table_name = $wpdb->prefix . 'tigerstyle_whiskers_consent_analytics';
$geo_stats = $wpdb->get_results($wpdb->prepare(
"SELECT
country_code,
COUNT(*) as total_requests,
SUM(CASE WHEN event_type = 'consent_granted' THEN 1 ELSE 0 END) as accepted,
ROUND((SUM(CASE WHEN event_type = 'consent_granted' THEN 1 ELSE 0 END) / COUNT(*)) * 100, 2) as acceptance_rate
FROM {$table_name}
WHERE date_created BETWEEN %s AND %s AND country_code != 'UNKNOWN'
GROUP BY country_code
ORDER BY total_requests DESC
LIMIT 20",
$start_date, $end_date
), ARRAY_A);
// Enhance with country names and GDPR status
foreach ($geo_stats as &$stat) {
$stat['country_name'] = $this->get_country_name($stat['country_code']);
$stat['is_gdpr_territory'] = $this->is_gdpr_territory($stat['country_code']);
$stat['privacy_law'] = $this->get_applicable_privacy_law($stat['country_code']);
}
return array(
'top_countries' => $geo_stats,
'gdpr_vs_non_gdpr' => $this->analyze_gdpr_vs_non_gdpr($geo_stats),
'regional_insights' => $this->get_regional_insights($geo_stats)
);
}
/**
* Get category preferences analysis
*/
private function get_category_preferences($start_date, $end_date) {
global $wpdb;
$table_name = $wpdb->prefix . 'tigerstyle_whiskers_consent_analytics';
$category_stats = array(
'analytics' => 0,
'marketing' => 0,
'preferences' => 0
);
$events = $wpdb->get_results($wpdb->prepare(
"SELECT event_data FROM {$table_name}
WHERE event_type = 'consent_granted' AND date_created BETWEEN %s AND %s",
$start_date, $end_date
));
$total_consents = count($events);
foreach ($events as $event) {
$data = json_decode($event->event_data, true);
$consent_categories = $data['consent_categories'] ?? array();
foreach ($category_stats as $category => $count) {
if (!empty($consent_categories[$category])) {
$category_stats[$category]++;
}
}
}
// Calculate percentages
$category_percentages = array();
foreach ($category_stats as $category => $count) {
$category_percentages[$category] = $total_consents > 0 ?
round(($count / $total_consents) * 100, 2) : 0;
}
return array(
'category_counts' => $category_stats,
'category_percentages' => $category_percentages,
'total_consents' => $total_consents,
'insights' => $this->analyze_category_preferences($category_percentages)
);
}
/**
* Get hourly patterns
*/
private function get_hourly_patterns($start_date, $end_date) {
global $wpdb;
$table_name = $wpdb->prefix . 'tigerstyle_whiskers_consent_analytics';
$hourly_stats = $wpdb->get_results($wpdb->prepare(
"SELECT
hour_created as hour,
COUNT(*) as total_requests,
SUM(CASE WHEN event_type = 'consent_granted' THEN 1 ELSE 0 END) as accepted
FROM {$table_name}
WHERE date_created BETWEEN %s AND %s
GROUP BY hour_created
ORDER BY hour_created ASC",
$start_date, $end_date
), ARRAY_A);
// Fill in missing hours
$hourly_data = array_fill(0, 24, array('hour' => 0, 'total_requests' => 0, 'accepted' => 0));
foreach ($hourly_stats as $stat) {
$hour = intval($stat['hour']);
$hourly_data[$hour] = $stat;
}
return array(
'hourly_distribution' => $hourly_data,
'peak_hours' => $this->identify_peak_hours($hourly_data),
'patterns_analysis' => $this->analyze_hourly_patterns($hourly_data)
);
}
/**
* AJAX handler for analytics data
*/
public function ajax_get_analytics_data() {
if (!current_user_can('manage_options')) {
wp_send_json_error('Insufficient permissions');
}
if (!wp_verify_nonce($_POST['nonce'], 'tigerstyle_whiskers_analytics')) {
wp_send_json_error('Security check failed');
}
$date_range = sanitize_text_field($_POST['date_range'] ?? '30_days');
$data_type = sanitize_text_field($_POST['data_type'] ?? 'overview');
$dashboard_data = $this->get_dashboard_data($date_range);
if (isset($dashboard_data[$data_type])) {
wp_send_json_success($dashboard_data[$data_type]);
} else {
wp_send_json_success($dashboard_data);
}
}
/**
* Inject analytics tracking script
*/
public function inject_analytics_tracking() {
// Only inject if consent analytics is enabled and we have consent
if (!$this->analytics_enabled) {
return;
}
?>
get_dashboard_data('30_days');
?>
render_analytics_controls(); ?>
render_overview_cards($dashboard_data['overview']); ?>
render_consent_trends_chart($dashboard_data['consent_trends']); ?>
render_geographic_map($dashboard_data['geographic_distribution']); ?>
render_category_analysis($dashboard_data['category_preferences']); ?>
render_hourly_patterns($dashboard_data['hourly_patterns']); ?>
get_current_detection();
}
return array('country_code' => 'UNKNOWN');
}
/**
* Calculate average daily requests
*/
private function calculate_avg_daily_requests($total_events, $start_date, $end_date) {
$start = new DateTime($start_date);
$end = new DateTime($end_date);
$days = $start->diff($end)->days + 1;
return $days > 0 ? round($total_events / $days, 2) : 0;
}
/**
* Fill in missing dates with zero values
*/
private function fill_missing_dates($trends, $start_date, $end_date) {
$filled_trends = array();
$start = new DateTime($start_date);
$end = new DateTime($end_date);
while ($start <= $end) {
$date = $start->format('Y-m-d');
$found = false;
foreach ($trends as $trend) {
if ($trend['date_created'] === $date) {
$filled_trends[] = $trend;
$found = true;
break;
}
}
if (!$found) {
$filled_trends[] = array(
'date_created' => $date,
'total_requests' => 0,
'accepted' => 0,
'denied' => 0
);
}
$start->modify('+1 day');
}
return $filled_trends;
}
/**
* Analyze trends data
*/
private function analyze_trends($trends) {
if (empty($trends)) {
return array(
'trend_direction' => 'stable',
'growth_rate' => 0,
'insights' => array()
);
}
$total_requests = array_sum(array_column($trends, 'total_requests'));
$total_accepted = array_sum(array_column($trends, 'accepted'));
// Calculate week-over-week change
$weeks = array_chunk($trends, 7);
$growth_rate = 0;
if (count($weeks) >= 2) {
$first_week = array_sum(array_column($weeks[0], 'total_requests'));
$last_week = array_sum(array_column(end($weeks), 'total_requests'));
if ($first_week > 0) {
$growth_rate = round((($last_week - $first_week) / $first_week) * 100, 2);
}
}
$trend_direction = 'stable';
if ($growth_rate > 5) {
$trend_direction = 'increasing';
} elseif ($growth_rate < -5) {
$trend_direction = 'decreasing';
}
return array(
'trend_direction' => $trend_direction,
'growth_rate' => $growth_rate,
'insights' => array(
'total_requests' => $total_requests,
'total_accepted' => $total_accepted,
'acceptance_rate' => $total_requests > 0 ? round(($total_accepted / $total_requests) * 100, 2) : 0
)
);
}
/**
* Analyze category preferences
*/
private function analyze_category_preferences($category_percentages) {
$insights = array();
foreach ($category_percentages as $category => $percentage) {
if ($percentage > 80) {
$insights[] = sprintf(__('%s cookies are widely accepted (%s%%)', 'tigerstyle-whiskers'), ucfirst($category), $percentage);
} elseif ($percentage < 20) {
$insights[] = sprintf(__('%s cookies have low acceptance (%s%%)', 'tigerstyle-whiskers'), ucfirst($category), $percentage);
}
}
if (empty($insights)) {
$insights[] = __('Category preferences are evenly distributed', 'tigerstyle-whiskers');
}
return $insights;
}
/**
* Identify peak hours
*/
private function identify_peak_hours($hourly_data) {
$peak_hours = array();
$max_requests = max(array_column($hourly_data, 'total_requests'));
if ($max_requests > 0) {
foreach ($hourly_data as $hour_data) {
if ($hour_data['total_requests'] >= $max_requests * 0.8) {
$peak_hours[] = $hour_data['hour'];
}
}
}
return $peak_hours;
}
/**
* Analyze hourly patterns
*/
private function analyze_hourly_patterns($hourly_data) {
$morning_requests = 0; // 6-12
$afternoon_requests = 0; // 12-18
$evening_requests = 0; // 18-24
$night_requests = 0; // 0-6
foreach ($hourly_data as $hour_data) {
$hour = intval($hour_data['hour']);
$requests = intval($hour_data['total_requests']);
if ($hour >= 6 && $hour < 12) {
$morning_requests += $requests;
} elseif ($hour >= 12 && $hour < 18) {
$afternoon_requests += $requests;
} elseif ($hour >= 18 && $hour < 24) {
$evening_requests += $requests;
} else {
$night_requests += $requests;
}
}
$total = $morning_requests + $afternoon_requests + $evening_requests + $night_requests;
return array(
'periods' => array(
'morning' => array('requests' => $morning_requests, 'percentage' => $total > 0 ? round(($morning_requests / $total) * 100, 2) : 0),
'afternoon' => array('requests' => $afternoon_requests, 'percentage' => $total > 0 ? round(($afternoon_requests / $total) * 100, 2) : 0),
'evening' => array('requests' => $evening_requests, 'percentage' => $total > 0 ? round(($evening_requests / $total) * 100, 2) : 0),
'night' => array('requests' => $night_requests, 'percentage' => $total > 0 ? round(($night_requests / $total) * 100, 2) : 0)
),
'peak_period' => $this->get_peak_period($morning_requests, $afternoon_requests, $evening_requests, $night_requests)
);
}
/**
* Get peak period
*/
private function get_peak_period($morning, $afternoon, $evening, $night) {
$periods = array(
'morning' => $morning,
'afternoon' => $afternoon,
'evening' => $evening,
'night' => $night
);
return array_search(max($periods), $periods);
}
/**
* Get country name from country code
*/
private function get_country_name($country_code) {
$countries = array(
'US' => 'United States',
'CA' => 'Canada',
'GB' => 'United Kingdom',
'DE' => 'Germany',
'FR' => 'France',
'IT' => 'Italy',
'ES' => 'Spain',
'NL' => 'Netherlands',
'BE' => 'Belgium',
'AU' => 'Australia',
'JP' => 'Japan',
'CN' => 'China',
'IN' => 'India',
'BR' => 'Brazil',
'MX' => 'Mexico',
'AR' => 'Argentina',
'RU' => 'Russia',
'KR' => 'South Korea',
'SG' => 'Singapore',
'HK' => 'Hong Kong',
'TW' => 'Taiwan',
'TH' => 'Thailand',
'MY' => 'Malaysia',
'ID' => 'Indonesia',
'PH' => 'Philippines',
'VN' => 'Vietnam',
'ZA' => 'South Africa',
'EG' => 'Egypt',
'NG' => 'Nigeria',
'KE' => 'Kenya'
);
return isset($countries[$country_code]) ? $countries[$country_code] : $country_code;
}
/**
* Check if country is in GDPR territory
*/
private function is_gdpr_territory($country_code) {
$gdpr_countries = array(
'AT', 'BE', 'BG', 'HR', 'CY', 'CZ', 'DK', 'EE', 'FI', 'FR',
'DE', 'GR', 'HU', 'IE', 'IT', 'LV', 'LT', 'LU', 'MT', 'NL',
'PL', 'PT', 'RO', 'SK', 'SI', 'ES', 'SE', 'IS', 'LI', 'NO'
);
return in_array($country_code, $gdpr_countries);
}
/**
* Get applicable privacy law for country
*/
private function get_applicable_privacy_law($country_code) {
if ($this->is_gdpr_territory($country_code)) {
return 'GDPR';
}
$privacy_laws = array(
'US' => 'CCPA/CPRA',
'CA' => 'PIPEDA',
'AU' => 'Privacy Act',
'JP' => 'APPI',
'KR' => 'PIPA',
'BR' => 'LGPD',
'IN' => 'PDPB',
'ZA' => 'POPIA',
'SG' => 'PDPA',
'MY' => 'PDPA',
'TH' => 'PDPA',
'PH' => 'DPA',
'VN' => 'Cybersecurity Law',
'CN' => 'PIPL',
'RU' => 'Personal Data Law'
);
return isset($privacy_laws[$country_code]) ? $privacy_laws[$country_code] : 'General Privacy Laws';
}
/**
* Analyze GDPR vs non-GDPR statistics
*/
private function analyze_gdpr_vs_non_gdpr($geo_stats) {
$gdpr_stats = array(
'total_requests' => 0,
'total_accepted' => 0,
'acceptance_rate' => 0
);
$non_gdpr_stats = array(
'total_requests' => 0,
'total_accepted' => 0,
'acceptance_rate' => 0
);
foreach ($geo_stats as $stat) {
if ($this->is_gdpr_territory($stat['country_code'])) {
$gdpr_stats['total_requests'] += intval($stat['total_requests']);
$gdpr_stats['total_accepted'] += intval($stat['accepted']);
} else {
$non_gdpr_stats['total_requests'] += intval($stat['total_requests']);
$non_gdpr_stats['total_accepted'] += intval($stat['accepted']);
}
}
$gdpr_stats['acceptance_rate'] = $gdpr_stats['total_requests'] > 0 ?
round(($gdpr_stats['total_accepted'] / $gdpr_stats['total_requests']) * 100, 2) : 0;
$non_gdpr_stats['acceptance_rate'] = $non_gdpr_stats['total_requests'] > 0 ?
round(($non_gdpr_stats['total_accepted'] / $non_gdpr_stats['total_requests']) * 100, 2) : 0;
return array(
'gdpr' => $gdpr_stats,
'non_gdpr' => $non_gdpr_stats,
'comparison' => array(
'acceptance_difference' => $gdpr_stats['acceptance_rate'] - $non_gdpr_stats['acceptance_rate'],
'total_requests_ratio' => $non_gdpr_stats['total_requests'] > 0 ?
round($gdpr_stats['total_requests'] / $non_gdpr_stats['total_requests'], 2) : 0
)
);
}
/**
* Get regional insights
*/
private function get_regional_insights($geo_stats) {
$insights = array();
$total_requests = array_sum(array_column($geo_stats, 'total_requests'));
$total_accepted = array_sum(array_column($geo_stats, 'accepted'));
if ($total_requests > 0) {
$overall_acceptance = round(($total_accepted / $total_requests) * 100, 2);
// Find countries with significantly different acceptance rates
foreach ($geo_stats as $stat) {
$country_acceptance = floatval($stat['acceptance_rate']);
$difference = $country_acceptance - $overall_acceptance;
if (abs($difference) > 10 && intval($stat['total_requests']) > 10) { // Only for statistically significant data
if ($difference > 0) {
$insights[] = sprintf(
__('%s shows %s%% higher consent acceptance than average (%s%%)', 'tigerstyle-whiskers'),
$this->get_country_name($stat['country_code']),
round($difference, 1),
$country_acceptance
);
} else {
$insights[] = sprintf(
__('%s shows %s%% lower consent acceptance than average (%s%%)', 'tigerstyle-whiskers'),
$this->get_country_name($stat['country_code']),
round(abs($difference), 1),
$country_acceptance
);
}
}
}
}
if (empty($insights)) {
$insights[] = __('Regional consent patterns are consistent across territories', 'tigerstyle-whiskers');
}
return $insights;
}
/**
* Get device analysis data
*/
private function get_device_analysis($start_date, $end_date) {
global $wpdb;
$table_name = $wpdb->prefix . 'tigerstyle_whiskers_consent_analytics';
// Get device type data from user agent analysis
$device_data = $wpdb->get_results($wpdb->prepare(
"SELECT
COUNT(*) as total_requests,
SUM(CASE WHEN event_type = 'consent_granted' THEN 1 ELSE 0 END) as accepted,
CASE
WHEN event_data LIKE '%%Mobile%%' OR event_data LIKE '%%Android%%' OR event_data LIKE '%%iPhone%%' THEN 'Mobile'
WHEN event_data LIKE '%%Tablet%%' OR event_data LIKE '%%iPad%%' THEN 'Tablet'
ELSE 'Desktop'
END as device_type
FROM {$table_name}
WHERE date_created BETWEEN %s AND %s
GROUP BY device_type
ORDER BY total_requests DESC",
$start_date, $end_date
), ARRAY_A);
$formatted_data = array();
$total_all_devices = 0;
// Check if we have data before iterating
if (!empty($device_data)) {
foreach ($device_data as $device) {
$total_requests = intval($device['total_requests']);
$accepted = intval($device['accepted']);
$acceptance_rate = $total_requests > 0 ? round(($accepted / $total_requests) * 100, 2) : 0;
$formatted_data[] = array(
'device_type' => $device['device_type'],
'total_requests' => $total_requests,
'accepted' => $accepted,
'denied' => $total_requests - $accepted,
'acceptance_rate' => $acceptance_rate
);
$total_all_devices += $total_requests;
}
}
// Add percentage of total traffic for each device
foreach ($formatted_data as &$device) {
$device['traffic_percentage'] = $total_all_devices > 0 ?
round(($device['total_requests'] / $total_all_devices) * 100, 2) : 0;
}
return array(
'devices' => $formatted_data,
'insights' => $this->get_device_insights($formatted_data)
);
}
/**
* Get device-specific insights
*/
private function get_device_insights($device_data) {
$insights = array();
if (empty($device_data)) {
$insights[] = __('No device data available for the selected period', 'tigerstyle-whiskers');
return $insights;
}
// Find device with highest acceptance rate
$highest_acceptance = 0;
$highest_device = '';
// Find device with most traffic
$highest_traffic = 0;
$traffic_leader = '';
foreach ($device_data as $device) {
if ($device['acceptance_rate'] > $highest_acceptance) {
$highest_acceptance = $device['acceptance_rate'];
$highest_device = $device['device_type'];
}
if ($device['traffic_percentage'] > $highest_traffic) {
$highest_traffic = $device['traffic_percentage'];
$traffic_leader = $device['device_type'];
}
}
if ($highest_device) {
$insights[] = sprintf(
__('%s users show the highest consent acceptance rate at %s%%', 'tigerstyle-whiskers'),
$highest_device,
$highest_acceptance
);
}
if ($traffic_leader) {
$insights[] = sprintf(
__('%s devices account for %s%% of total traffic', 'tigerstyle-whiskers'),
$traffic_leader,
$highest_traffic
);
}
// Check for mobile-specific patterns
foreach ($device_data as $device) {
if ($device['device_type'] === 'Mobile' && $device['acceptance_rate'] < 50) {
$insights[] = __('Mobile users show lower consent acceptance - consider optimizing mobile consent experience', 'tigerstyle-whiskers');
break;
}
}
return $insights;
}
/**
* Get compliance insights
*/
private function get_compliance_insights($start_date, $end_date) {
global $wpdb;
$table_name = $wpdb->prefix . 'tigerstyle_whiskers_consent_analytics';
$insights = array();
// Get overall statistics
$total_requests = $wpdb->get_var($wpdb->prepare(
"SELECT COUNT(*) FROM {$table_name} WHERE date_created BETWEEN %s AND %s",
$start_date, $end_date
));
$consent_granted = $wpdb->get_var($wpdb->prepare(
"SELECT COUNT(*) FROM {$table_name} WHERE event_type = 'consent_granted' AND date_created BETWEEN %s AND %s",
$start_date, $end_date
));
if ($total_requests == 0) {
$insights[] = __('No consent data available for the selected period', 'tigerstyle-whiskers');
return $insights;
}
$acceptance_rate = round(($consent_granted / $total_requests) * 100, 2);
// Compliance insights based on acceptance rates
if ($acceptance_rate >= 75) {
$insights[] = sprintf(
__('Excellent compliance: %s%% consent acceptance rate indicates clear privacy communication', 'tigerstyle-whiskers'),
$acceptance_rate
);
} elseif ($acceptance_rate >= 50) {
$insights[] = sprintf(
__('Good compliance: %s%% acceptance rate. Consider reviewing consent banner clarity', 'tigerstyle-whiskers'),
$acceptance_rate
);
} else {
$insights[] = sprintf(
__('Low acceptance rate (%s%%). Review consent banner design and messaging for GDPR compliance', 'tigerstyle-whiskers'),
$acceptance_rate
);
}
// Check for GDPR territory compliance
$gdpr_countries = $wpdb->get_var($wpdb->prepare(
"SELECT COUNT(DISTINCT country_code) FROM {$table_name}
WHERE country_code IN ('DE', 'FR', 'IT', 'ES', 'NL', 'BE', 'AT', 'SE', 'DK', 'FI', 'IE', 'PT', 'GR', 'LU', 'CY', 'MT', 'SI', 'SK', 'EE', 'LV', 'LT', 'PL', 'CZ', 'HU', 'RO', 'BG', 'HR')
AND date_created BETWEEN %s AND %s",
$start_date, $end_date
));
if ($gdpr_countries > 0) {
$insights[] = sprintf(
__('GDPR compliance active: Serving users from %d EU territories', 'tigerstyle-whiskers'),
$gdpr_countries
);
}
// Check consent withdrawal patterns
$consent_withdrawn = $wpdb->get_var($wpdb->prepare(
"SELECT COUNT(*) FROM {$table_name} WHERE event_type = 'consent_withdrawn' AND date_created BETWEEN %s AND %s",
$start_date, $end_date
));
if ($consent_withdrawn > 0) {
$withdrawal_rate = round(($consent_withdrawn / $total_requests) * 100, 2);
if ($withdrawal_rate > 10) {
$insights[] = sprintf(
__('High withdrawal rate (%s%%). Consider reviewing data processing transparency', 'tigerstyle-whiskers'),
$withdrawal_rate
);
}
}
// Performance insight
if ($total_requests > 1000) {
$insights[] = __('High-volume consent processing - ensure optimal performance monitoring', 'tigerstyle-whiskers');
}
return $insights;
}
/**
* Get performance metrics
*/
private function get_performance_metrics($start_date, $end_date) {
global $wpdb;
$table_name = $wpdb->prefix . 'tigerstyle_whiskers_consent_analytics';
// Get basic performance metrics
$total_events = $wpdb->get_var($wpdb->prepare(
"SELECT COUNT(*) FROM {$table_name} WHERE date_created BETWEEN %s AND %s",
$start_date, $end_date
));
$unique_sessions = $wpdb->get_var($wpdb->prepare(
"SELECT COUNT(DISTINCT session_id_hash) FROM {$table_name} WHERE date_created BETWEEN %s AND %s",
$start_date, $end_date
));
$avg_events_per_session = $unique_sessions > 0 ? round($total_events / $unique_sessions, 2) : 0;
return array(
'total_events' => intval($total_events),
'unique_sessions' => intval($unique_sessions),
'events_per_session' => $avg_events_per_session,
'data_points_collected' => intval($total_events),
'performance_score' => $this->calculate_performance_score($total_events, $unique_sessions)
);
}
/**
* Calculate performance score
*/
private function calculate_performance_score($total_events, $unique_sessions) {
if ($unique_sessions == 0) {
return 0;
}
$events_per_session = $total_events / $unique_sessions;
// Score based on data collection efficiency
if ($events_per_session <= 2) {
return 95; // Excellent - minimal data collection
} elseif ($events_per_session <= 5) {
return 85; // Good
} elseif ($events_per_session <= 10) {
return 70; // Average
} else {
return 50; // High data collection - review for privacy compliance
}
}
/**
* Render analytics controls (time period selector, etc.)
*/
private function render_analytics_controls() {
?>