setConsent('denied'); do_action('slimstat_consent_revoked'); wp_send_json_success([ 'message' => __('Consent revoked and cookie deleted.', 'wp-slimstat'), ]); } /** * Register AJAX handlers for consent changes * * @return void */ public static function registerAjaxHandlers() { add_action('wp_ajax_slimstat_consent_revoked', [self::class, 'handleConsentRevoked']); add_action('wp_ajax_nopriv_slimstat_consent_revoked', [self::class, 'handleConsentRevoked']); add_action('wp_ajax_slimstat_gdpr_consent', [self::class, 'handleBannerConsent']); add_action('wp_ajax_nopriv_slimstat_gdpr_consent', [self::class, 'handleBannerConsent']); } /** * Handle GDPR banner consent via AJAX * * @param bool $return_json Whether to return JSON response (default: true) * @param array $data Optional data array with 'nonce', 'consent', 'pageview_id' keys. If empty, reads from $_POST. * @return bool|void Returns true on success, false on error, or outputs JSON if $return_json is true */ public static function handleBannerConsent(bool $return_json = true, array $data = []) { // Use provided data or fall back to $_POST $nonce = ''; $consent = ''; $pageview_id_raw = ''; if (!empty($data)) { $nonce = isset($data['nonce']) ? sanitize_text_field($data['nonce']) : ''; $consent = isset($data['consent']) ? sanitize_text_field($data['consent']) : ''; $pageview_id_raw = isset($data['pageview_id']) ? sanitize_text_field($data['pageview_id']) : ''; } else { $nonce = isset($_POST['nonce']) ? sanitize_text_field(wp_unslash($_POST['nonce'])) : ''; $consent = isset($_POST['consent']) ? sanitize_text_field(wp_unslash($_POST['consent'])) : ''; $pageview_id_raw = isset($_POST['pageview_id']) ? sanitize_text_field(wp_unslash($_POST['pageview_id'])) : ''; } if (empty($nonce) || !wp_verify_nonce($nonce, 'wp_rest')) { if ($return_json) { wp_send_json_error([ 'message' => __('Invalid security token.', 'wp-slimstat'), ]); return; } return false; } if (empty(\wp_slimstat::$settings['use_slimstat_banner']) || 'on' !== \wp_slimstat::$settings['use_slimstat_banner']) { if ($return_json) { wp_send_json_error([ 'message' => __('SlimStat banner is not enabled.', 'wp-slimstat'), ]); return; } return false; } if (!in_array($consent, ['accepted', 'denied'], true)) { if ($return_json) { wp_send_json_error([ 'message' => __('Invalid consent value.', 'wp-slimstat'), ]); return; } return false; } $gdpr_service = new \SlimStat\Services\GDPRService(\wp_slimstat::$settings); $result = $gdpr_service->setConsent($consent); if (!$result) { if ($return_json) { wp_send_json_error([ 'message' => __('Failed to set consent cookie.', 'wp-slimstat'), ]); return; } return false; } do_action('slimstat_gdpr_consent_changed', $consent); $parsed_consent = \SlimStat\Utils\Consent::normalizeConsent($consent); $action = ('accepted' === $consent) ? 'grant' : 'revoke'; // If consent granted via banner, upgrade current pageview from anonymous to PII if ('accepted' === $consent) { if (!empty($pageview_id_raw)) { $pageview_id = \SlimStat\Tracker\Utils::getValueWithoutChecksum($pageview_id_raw); if (false !== $pageview_id && $pageview_id > 0) { $pageview_id = intval($pageview_id); $stat = IPHashProvider::upgradeToPii([]); if (!empty($GLOBALS['current_user']->ID)) { $stat['username'] = $GLOBALS['current_user']->data->user_login; $stat['email'] = $GLOBALS['current_user']->data->user_email; $stat['notes'] = '[user:' . $GLOBALS['current_user']->data->ID . ']'; } $table = $GLOBALS['wpdb']->prefix . 'slim_stats'; $update_data = []; if (!empty($stat['ip'])) { $update_data['ip'] = $stat['ip']; } if (!empty($stat['other_ip'])) { $update_data['other_ip'] = $stat['other_ip']; } if (!empty($stat['username'])) { $update_data['username'] = $stat['username']; } if (!empty($stat['email'])) { $update_data['email'] = $stat['email']; } if (!empty($update_data)) { $GLOBALS['wpdb']->update( $table, $update_data, ['id' => $pageview_id], array_fill(0, count($update_data), '%s'), ['%d'] ); } // Append user note if not already present if (!empty($stat['notes'])) { $existing_note = $GLOBALS['wpdb']->get_var( $GLOBALS['wpdb']->prepare( "SELECT notes FROM {$table} WHERE id = %d AND notes LIKE %s LIMIT 1", $pageview_id, '%' . $GLOBALS['wpdb']->esc_like($stat['notes']) . '%' ) ); if (empty($GLOBALS['wpdb']->last_error) && null === $existing_note) { $GLOBALS['wpdb']->query( $GLOBALS['wpdb']->prepare( "UPDATE {$table} SET notes = CONCAT(IFNULL(notes, ''), %s) WHERE id = %d", $stat['notes'], $pageview_id ) ); } } do_action('slimstat_consent_granted', $pageview_id, $stat); } } } if ($return_json) { wp_send_json_success([ 'success' => true, 'message' => ('accepted' === $consent) ? __('Consent granted.', 'wp-slimstat') : __('Consent denied.', 'wp-slimstat'), 'consent' => $consent, ]); } return true; } }