' . esc_html__('Configure your Airefs tracking settings below.', 'airefs-ai-search-analytics-tracking') . '

'; } /** * Advanced section callback */ public static function advanced_section_callback() { echo '

' . esc_html__('Advanced configuration options. Only change these if you know what you\'re doing.', 'airefs-ai-search-analytics-tracking') . '

'; } /** * Access token field */ public static function access_token_field() { $options = get_option(AIREFS_TRACKING_OPTIONS_NAME, array()); $value = isset($options['access_token']) ? $options['access_token'] : ''; echo ''; echo ''; echo '

' . sprintf( esc_html__('Enter your Airefs Access Token. You can find this in your Airefs Dashboard.', 'airefs-ai-search-analytics-tracking'), '', '' ) . '

'; } /** * Tracking enabled field */ public static function tracking_enabled_field() { $options = get_option(AIREFS_TRACKING_OPTIONS_NAME, array()); $value = isset($options['tracking_enabled']) ? $options['tracking_enabled'] : true; echo ''; echo '

' . esc_html__('When enabled, the plugin will track clicks from AI search results to your website.', 'airefs-ai-search-analytics-tracking') . '

'; } /** * Cache vary field */ public static function cache_vary_field() { $options = get_option(AIREFS_TRACKING_OPTIONS_NAME, array()); $value = isset($options['enable_cache_vary']) ? $options['enable_cache_vary'] : false; echo ''; echo '

' . esc_html__('When enabled, adds User-Agent to cache vary headers for better AI bot detection. This may impact site performance by reducing cache effectiveness.', 'airefs-ai-search-analytics-tracking') . '

'; } public static function url_query_allowlist_field() { $options = get_option(AIREFS_TRACKING_OPTIONS_NAME, array()); $names = airefs_tracking_query_allowlist(isset($options['url_query_allowlist']) ? $options['url_query_allowlist'] : array()); echo ''; echo '

' . esc_html__('Comma-separated query names that identify different content, for example countries. WordPress p and page_id are always preserved when valid. Up to 16 names, using letters, numbers, underscores or hyphens and starting with a letter. Names are case-sensitive. Never add personal data; credential, session and tracking names are blocked. New settings apply only to newly captured events.', 'airefs-ai-search-analytics-tracking') . '

'; } /** * API endpoint field */ public static function api_endpoint_field() { $options = get_option(AIREFS_TRACKING_OPTIONS_NAME, array()); $value = isset($options['api_endpoint']) ? $options['api_endpoint'] : 'https://api.getairefs.com'; echo '
'; echo '' . esc_html__('API Endpoint Configuration', 'airefs-ai-search-analytics-tracking') . ''; echo ''; echo '

' . esc_html__('The Airefs API endpoint. Only change this if instructed by Airefs support.', 'airefs-ai-search-analytics-tracking') . '

'; echo '
'; } /** * Settings page */ public static function settings_page() { // Check user capabilities if (!current_user_can('manage_options')) { return; } // Get options for connection test $options = get_option(AIREFS_TRACKING_OPTIONS_NAME, array()); $has_access_token = !empty($options['access_token']); ?>

  1. airefs.com' ); ?>
0 ? __('Events are queued for background delivery.', 'airefs-ai-search-analytics-tracking') : ($health['last_success'] > 0 ? __('The last delivery was confirmed; no events are waiting.', 'airefs-ai-search-analytics-tracking') : __('Waiting for the first confirmed delivery.', 'airefs-ai-search-analytics-tracking'))))); ?>

0): ?>

0 && $health['last_rejected'] >= time() - 600) { return __('Some new events could not be saved. Check queue storage and delivery errors; already saved events are retained.', 'airefs-ai-search-analytics-tracking'); } if ($health['blocked'] > 0) { return __('Some saved events need attention before they can be delivered.', 'airefs-ai-search-analytics-tracking'); } if ($health['error'] !== '' || $health['scheduler_error'] !== '') { return __('Background delivery needs attention. Saved events are retained.', 'airefs-ai-search-analytics-tracking'); } if ($health['capacity_bytes'] > 0 && $health['bytes'] >= $health['capacity_bytes'] * 0.8) { return __('Queue storage is nearly full. Check delivery before new events can no longer be saved.', 'airefs-ai-search-analytics-tracking'); } if ($health['count'] > 0 && $health['oldest'] > 0 && $health['oldest'] < time() - 600) { return __('Delivery is delayed: events have been waiting for more than ten minutes.', 'airefs-ai-search-analytics-tracking'); } return ''; } /** * Sanitize settings */ public static function sanitize_settings($input) { $existing = get_option(AIREFS_TRACKING_OPTIONS_NAME, array()); $sanitized = array(); foreach (array('plugin_version', 'htaccess_cleanup_complete') as $key) { if (isset($existing[$key])) { $sanitized[$key] = $existing[$key]; } } // Sanitize access token if (isset($input['access_token'])) { $sanitized['access_token'] = sanitize_text_field($input['access_token']); } // Sanitize tracking enabled $sanitized['tracking_enabled'] = isset($input['tracking_enabled']) ? (bool) $input['tracking_enabled'] : false; // Sanitize cache vary enabled $sanitized['enable_cache_vary'] = isset($input['enable_cache_vary']) ? (bool) $input['enable_cache_vary'] : false; $sanitized['url_query_allowlist'] = airefs_tracking_query_allowlist(isset($existing['url_query_allowlist']) ? $existing['url_query_allowlist'] : array()); if (isset($input['url_query_allowlist'])) { $raw = $input['url_query_allowlist']; $names = is_string($raw) ? (trim($raw) === '' ? array() : explode(',', $raw)) : $raw; $valid = is_array($names); $allowed = array(); if ($valid) { foreach ($names as $name) { if (!is_string($name) || !airefs_tracking_valid_query_name(trim($name))) { $valid = false; break; } $allowed[] = trim($name); } } $allowed = array_values(array_unique(array_diff($allowed, array('p', 'page_id')))); if ($valid && count($allowed) <= 16) { $sanitized['url_query_allowlist'] = airefs_tracking_query_allowlist($allowed); } else { add_settings_error(AIREFS_TRACKING_OPTIONS_NAME, 'invalid_url_query_allowlist', __('Content query parameters were not changed. Enter at most 16 names starting with a letter, with up to 64 letters, numbers, underscores or hyphens each. Credential, session and tracking names are not allowed.', 'airefs-ai-search-analytics-tracking')); } } // Sanitize API endpoint if (isset($input['api_endpoint'])) { $endpoint = esc_url_raw($input['api_endpoint']); $sanitized['api_endpoint'] = airefs_tracking_origin($endpoint) ? rtrim($endpoint, '/') : 'https://api.getairefs.com'; } return $sanitized; } /** * Admin notices */ public static function admin_notices() { $options = get_option(AIREFS_TRACKING_OPTIONS_NAME, array()); if (current_user_can('manage_options')) { $health = AirefsTrackingQueue::health(); $warning = self::delivery_warning($health); if ($warning !== '') { $notice_class = $health['storage_ready'] ? 'notice-warning' : 'notice-error'; echo '

Airefs: ' . esc_html($warning) . ' ' . esc_html__('View Airefs delivery status', 'airefs-ai-search-analytics-tracking') . '

'; } if (isset($options['htaccess_cleanup_complete']) && !$options['htaccess_cleanup_complete']) { echo '

' . esc_html__('Airefs could not remove its legacy .htaccess block. Make the file writable or remove only the block marked “Airefs AI Bot Exclusion”. Cleanup will retry automatically.', 'airefs-ai-search-analytics-tracking') . '

'; } elseif (get_transient('airefs_cleanup_completed')) { echo '

' . esc_html__('Airefs legacy .htaccess cleanup completed.', 'airefs-ai-search-analytics-tracking') . '

'; delete_transient('airefs_cleanup_completed'); } } // Show notice if access token is not set if (empty($options['access_token']) && current_user_can('manage_options')) { $settings_url = admin_url('options-general.php?page=' . self::SETTINGS_PAGE); ?>

', '' ); ?>

__('No Access Token configured.', 'airefs-ai-search-analytics-tracking') )); } $api_endpoint = isset($options['api_endpoint']) ? $options['api_endpoint'] : 'https://api.getairefs.com'; // Test API connection $response = wp_remote_get($api_endpoint . '/health', array( 'headers' => array( 'Authorization' => 'Bearer ' . $options['access_token'], 'User-Agent' => AIREFS_TRACKING_UA, ), 'timeout' => 10, 'redirection' => 0, 'limit_response_size' => 4096, )); if (is_wp_error($response)) { wp_send_json_error(array( // translators: %s is the error message 'message' => sprintf(__('Connection failed: %s', 'airefs-ai-search-analytics-tracking'), $response->get_error_message()) )); } $status_code = wp_remote_retrieve_response_code($response); $body = json_decode(wp_remote_retrieve_body($response), true); if ($status_code === 200 && is_array($body) && isset($body['delivery_protocol'], $body['site_id']) && $body['delivery_protocol'] === 1 && is_string($body['site_id']) && $body['site_id'] !== '') { $health = AirefsTrackingQueue::health(); if (!$health['storage_ready']) { wp_send_json_error(array( 'api_connected' => true, 'storage_ready' => false, 'message' => __('API connected. Tracking is not ready: local storage setup failed. Use Retry storage setup under Background delivery after your host resolves the database issue.', 'airefs-ai-search-analytics-tracking') )); } wp_send_json_success(array( 'api_connected' => true, 'storage_ready' => true, 'message' => empty($options['tracking_enabled']) ? __('API connected. Local storage is ready, but tracking is paused.', 'airefs-ai-search-analytics-tracking') : __('API connected. Local storage is ready. Check Background delivery for confirmed event delivery.', 'airefs-ai-search-analytics-tracking') )); } elseif ($status_code === 200) { wp_send_json_error(array( 'message' => __('The endpoint responded but does not support confirmed delivery. Saved events will wait until the endpoint is updated.', 'airefs-ai-search-analytics-tracking') )); } else { wp_send_json_error(array( // translators: %d is the HTTP status code 'message' => sprintf(__('Connection failed with status code: %d', 'airefs-ai-search-analytics-tracking'), $status_code) )); } } // Initialize admin functionality AirefsTrackingAdmin::init(); // Register AJAX handlers add_action('wp_ajax_airefs_test_connection', 'airefs_test_connection_handler'); function airefs_retry_delivery_handler() { if (!current_user_can('manage_options')) { wp_die(esc_html__('Insufficient permissions.', 'airefs-ai-search-analytics-tracking'), '', array('response' => 403)); } check_admin_referer('airefs_retry_delivery'); $result = AirefsTrackingQueue::retry_now(); $status = $result === true ? 'scheduled' : 'failed'; wp_safe_redirect(add_query_arg('airefs_delivery', $status, admin_url('options-general.php?page=' . AirefsTrackingAdmin::SETTINGS_PAGE))); exit; } add_action('admin_post_airefs_retry_delivery', 'airefs_retry_delivery_handler'); function airefs_retry_setup_handler() { if (!current_user_can('manage_options')) { wp_die(esc_html__('Insufficient permissions.', 'airefs-ai-search-analytics-tracking'), '', array('response' => 403)); } check_admin_referer('airefs_retry_setup'); $ready = AirefsTrackingQueue::retry_setup(); wp_safe_redirect(add_query_arg('airefs_setup', $ready ? 'ready' : 'failed', admin_url('options-general.php?page=' . AirefsTrackingAdmin::SETTINGS_PAGE))); exit; } add_action('admin_post_airefs_retry_setup', 'airefs_retry_setup_handler');