should_ignore_request()) { return; } if (! is_singular()) { return; } $post_id = get_queried_object_id(); if (! $post_id || 'publish' !== get_post_status($post_id)) { return; } if (is_user_logged_in()) { $settings = A360_Insights_Settings::get(); if (! empty($settings['exclude_logged_in_users'])) { return; } if (! empty($settings['exclude_administrators']) && current_user_can('manage_options')) { return; } } if (! A360_Insights_Settings::should_track_post($post_id)) { return; } $source_data = $this->source_data(); A360_Insights_DB::insert_view($post_id, $source_data); $tracked = true; } /** * Store temporary referrer diagnostics for every WordPress request. * * @return void */ public function maybe_debug_referrer() { static $debugged = false; if ($debugged) { return; } $post_id = is_singular() ? get_queried_object_id() : 0; $data = $this->debug_source_data(); A360_Insights_DB::insert_referrer_debug($post_id, $data); $debugged = true; } /** * Enqueue browser-side referrer repair script. * * @return void */ public function enqueue_referrer_script() { if (is_admin() || is_preview() || is_feed() || is_robots()) { return; } if (! is_singular()) { return; } $post_id = get_queried_object_id(); if (! $post_id || 'publish' !== get_post_status($post_id)) { return; } if (is_user_logged_in()) { $settings = A360_Insights_Settings::get(); if (! empty($settings['exclude_logged_in_users'])) { return; } if (! empty($settings['exclude_administrators']) && current_user_can('manage_options')) { return; } } if (! A360_Insights_Settings::should_track_post($post_id)) { return; } wp_enqueue_script( 'a360-insights-referrer', A360_INSIGHTS_URL . 'assets/referrer.js', array(), A360_INSIGHTS_VERSION, true ); wp_localize_script( 'a360-insights-referrer', 'a360InsightsReferrer', array( 'ajax_url' => admin_url('admin-ajax.php'), 'nonce' => wp_create_nonce('a360_js_referrer'), 'post_id' => absint($post_id), ) ); wp_enqueue_script( 'a360-insights-scroll', A360_INSIGHTS_URL . 'assets/scroll.js', array(), A360_INSIGHTS_VERSION, true ); wp_localize_script( 'a360-insights-scroll', 'a360InsightsEngagement', array( 'ajax_url' => admin_url('admin-ajax.php'), 'nonce' => wp_create_nonce('a360_engagement_event'), 'session_nonce' => wp_create_nonce('a360_session'), 'post_id' => absint($post_id), ) ); } /** * Enqueue small public counter styles. * * @return void */ public function enqueue_public_counter_style() { if (is_admin()) { return; } wp_register_style('a360-insights-counter', false, array(), A360_INSIGHTS_VERSION); wp_enqueue_style('a360-insights-counter'); wp_add_inline_style( 'a360-insights-counter', '.a360-insights-public-counter{display:inline-flex;align-items:center;gap:8px;padding:8px 12px;border:1px solid rgba(15,23,42,.12);border-radius:999px;background:#fff;color:#111827;box-shadow:0 8px 24px rgba(15,23,42,.12);font:600 14px/1.2 -apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;text-decoration:none}.a360-insights-public-counter-fixed{position:fixed;right:18px;bottom:18px;z-index:9999}.a360-insights-public-counter-icon{display:inline-flex;align-items:flex-end;gap:2px;height:16px;color:#2563eb}.a360-insights-public-counter-icon span{display:block;width:4px;background:currentColor;border-radius:2px 2px 0 0}.a360-insights-public-counter-icon span:nth-child(1){height:6px}.a360-insights-public-counter-icon span:nth-child(2){height:10px}.a360-insights-public-counter-icon span:nth-child(3){height:14px}.a360-insights-public-counter strong{font-weight:800}.a360-insights-public-counter small{font-size:12px;font-weight:600;color:#64748b}@media (max-width:600px){.a360-insights-public-counter-fixed{right:12px;bottom:12px;padding:7px 10px;font-size:13px}}' ); } /** * Render the optional public footer counter. * * @return void */ public function render_public_counter() { if (is_admin() || is_preview() || is_feed() || is_robots()) { return; } $settings = A360_Insights_Settings::get(); if (empty($settings['public_counter_enabled'])) { return; } echo wp_kses_post( $this->build_public_counter( (string) ($settings['public_counter_scope'] ?? 'site'), (string) ($settings['public_counter_label'] ?? __('views', 'a360-insights')), 'a360-insights-public-counter a360-insights-public-counter-fixed' ) ); } /** * Render a manual public counter shortcode. * * @param array $atts Shortcode attributes. * @return string */ public function views_counter_shortcode($atts) { $settings = A360_Insights_Settings::get(); $atts = shortcode_atts( array( 'scope' => (string) ($settings['public_counter_scope'] ?? 'site'), 'label' => (string) ($settings['public_counter_label'] ?? __('views', 'a360-insights')), ), (array) $atts, 'a360_views_counter' ); return $this->build_public_counter((string) $atts['scope'], (string) $atts['label'], 'a360-insights-public-counter'); } /** * Build public counter markup. * * @param string $scope Counter scope. * @param string $label Counter label. * @param string $class CSS class list. * @return string */ private function build_public_counter($scope, $label, $class) { $scope = sanitize_key($scope); if (! in_array($scope, array('site', 'content'), true)) { $scope = 'site'; } $views = 'content' === $scope ? $this->current_content_views() : A360_Insights_DB::get_site_total_views(); if ('content' === $scope && null === $views) { return ''; } $label = sanitize_text_field($label); if ('' === trim($label)) { $label = __('views', 'a360-insights'); } return sprintf( '%2$s%3$s', esc_attr($class), esc_html(number_format_i18n((int) $views)), esc_html($label) ); } /** * Get views for the current singular content item. * * @return int|null */ private function current_content_views() { if (! is_singular()) { return null; } $post_id = get_queried_object_id(); if (! $post_id || 'publish' !== get_post_status($post_id)) { return null; } return A360_Insights_DB::get_total_views($post_id); } /** * Update the last direct view with document.referrer detected in the browser. * * @return void */ public function save_js_referrer() { check_ajax_referer('a360_js_referrer', 'nonce'); $post_id = isset($_POST['post_id']) ? absint($_POST['post_id']) : 0; $referrer_url = isset($_POST['referrer']) ? esc_url_raw(wp_unslash($_POST['referrer'])) : ''; $current_url = isset($_POST['url']) ? esc_url_raw(wp_unslash($_POST['url'])) : ''; if (! $post_id || ! $referrer_url || 'publish' !== get_post_status($post_id)) { wp_send_json_error(); } if (! A360_Insights_Settings::should_track_post($post_id)) { wp_send_json_error(); } $referrer_host = wp_parse_url($referrer_url, PHP_URL_HOST); $referrer_host = is_string($referrer_host) ? strtolower(sanitize_text_field($referrer_host)) : ''; if (! $referrer_host) { wp_send_json_error(); } $site_host = wp_parse_url(home_url(), PHP_URL_HOST); $site_host = is_string($site_host) ? strtolower(preg_replace('/^www\./', '', $site_host)) : ''; $normalized_referrer_host = strtolower(preg_replace('/^www\./', '', $referrer_host)); if ($site_host && $normalized_referrer_host === $site_host) { wp_send_json_success(); } $current_path = $current_url ? wp_parse_url($current_url, PHP_URL_PATH) : ''; $current_path = is_string($current_path) ? $current_path : ''; if ($this->is_google_business_profile_visit($referrer_host, $referrer_url, $current_path)) { $source = 'google_business_profile'; } else { $source = $this->classify_referrer($referrer_host, $referrer_url); } if ('internal' === $source) { wp_send_json_success(); } A360_Insights_DB::update_recent_direct_view( $post_id, array( 'source' => $source, 'referrer_host' => $referrer_host, 'referrer_url' => $referrer_url, ) ); wp_send_json_success(); } /** * Save anonymous browser session metadata for the latest page view. * * @return void */ public function save_session() { check_ajax_referer('a360_session', 'nonce'); $post_id = isset($_POST['post_id']) ? absint($_POST['post_id']) : 0; $session_id = isset($_POST['session_id']) ? sanitize_text_field(wp_unslash($_POST['session_id'])) : ''; $referrer_url = isset($_POST['referrer']) ? esc_url_raw(wp_unslash($_POST['referrer'])) : ''; $current_url = isset($_POST['url']) ? esc_url_raw(wp_unslash($_POST['url'])) : ''; $landing_url = isset($_POST['landing_url']) ? esc_url_raw(wp_unslash($_POST['landing_url'])) : $current_url; if (! $post_id || ! $session_id || 'publish' !== get_post_status($post_id)) { wp_send_json_error(); } if (! A360_Insights_Settings::should_track_post($post_id)) { wp_send_json_error(); } $source_data = $this->source_data_from_browser($referrer_url, $current_url, $landing_url); $saved = A360_Insights_DB::upsert_session($post_id, $session_id, $source_data); if (! $saved) { wp_send_json_error(); } wp_send_json_success(); } /** * Store a browser engagement event such as scroll depth. * * @return void */ public function save_engagement_event() { check_ajax_referer('a360_engagement_event', 'nonce'); $post_id = isset($_POST['post_id']) ? absint($_POST['post_id']) : 0; $event_type = isset($_POST['event_type']) ? sanitize_key(wp_unslash($_POST['event_type'])) : ''; $event_value = isset($_POST['event_value']) ? absint($_POST['event_value']) : 0; $event_label = isset($_POST['event_label']) ? sanitize_text_field(wp_unslash($_POST['event_label'])) : ''; $referrer_url = isset($_POST['referrer']) ? esc_url_raw(wp_unslash($_POST['referrer'])) : ''; $current_url = isset($_POST['url']) ? esc_url_raw(wp_unslash($_POST['url'])) : ''; $session_id = isset($_POST['session_id']) ? sanitize_text_field(wp_unslash($_POST['session_id'])) : ''; if (! $post_id || 'publish' !== get_post_status($post_id)) { wp_send_json_error(); } if (! in_array($event_type, A360_Insights_DB::allowed_engagement_events(), true)) { wp_send_json_error(); } if (0 !== $event_value && ! in_array($event_value, array(25, 50, 75, 90), true)) { wp_send_json_error(); } if (! A360_Insights_Settings::should_track_post($post_id)) { wp_send_json_error(); } $referrer_host = $referrer_url ? wp_parse_url($referrer_url, PHP_URL_HOST) : ''; $referrer_host = is_string($referrer_host) ? strtolower(sanitize_text_field($referrer_host)) : ''; $current_path = $current_url ? wp_parse_url($current_url, PHP_URL_PATH) : ''; $current_path = is_string($current_path) ? sanitize_text_field($current_path) : ''; if ($referrer_host && $this->is_google_business_profile_visit($referrer_host, $referrer_url, $current_path)) { $source = 'google_business_profile'; } elseif ($referrer_host) { $source = $this->classify_referrer($referrer_host, $referrer_url); } else { $source = 'direct'; } if ('internal' === $source) { $source = 'direct'; $referrer_host = ''; $referrer_url = ''; } $inserted = A360_Insights_DB::insert_engagement_event( $post_id, array( 'event_type' => $event_type, 'event_value' => $event_value, 'event_label' => $event_label, 'session_id' => $session_id, 'source' => $source, 'referrer_host' => $referrer_host, 'referrer_url' => $referrer_url, 'request_path' => $current_path, ) ); if (! $inserted) { wp_send_json_error(); } wp_send_json_success(); } /** * Determine whether the current request should be ignored before tracking. * * @return bool */ private function should_ignore_request() { $settings = A360_Insights_Settings::get(); if (! empty($settings['exclude_cron']) && wp_doing_cron()) { return true; } if (! empty($settings['exclude_cli']) && defined('WP_CLI') && WP_CLI) { return true; } if (! empty($settings['ignore_prefetch']) && $this->is_prefetch_request()) { return true; } if (! empty($settings['exclude_bots']) && $this->is_bot_request()) { return true; } return false; } /** * Detect common browser prefetch, prerender and preview requests. * * @return bool */ private function is_prefetch_request() { $headers = array( 'HTTP_X_MOZ', 'HTTP_PURPOSE', 'HTTP_SEC_PURPOSE', 'HTTP_X_PURPOSE', ); foreach ($headers as $header) { if (empty($_SERVER[$header])) { continue; } $value = strtolower(sanitize_text_field(wp_unslash($_SERVER[$header]))); if (false !== strpos($value, 'prefetch') || false !== strpos($value, 'prerender') || false !== strpos($value, 'preview')) { return true; } } return false; } /** * Detect common bots, crawlers, link previewers and uptime monitors. * * @return bool */ private function is_bot_request() { if (empty($_SERVER['HTTP_USER_AGENT'])) { return false; } $user_agent = strtolower(sanitize_text_field(wp_unslash($_SERVER['HTTP_USER_AGENT']))); if ('' === $user_agent) { return false; } $patterns = array( 'bot', 'crawler', 'spider', 'crawl', 'slurp', 'googlebot', 'bingbot', 'duckduckbot', 'baiduspider', 'yandex', 'sogou', 'exabot', 'facebot', 'facebookexternalhit', 'linkedinbot', 'twitterbot', 'pinterest', 'whatsapp', 'telegrambot', 'discordbot', 'skypeuripreview', 'vkshare', 'ahrefs', 'semrush', 'mj12bot', 'dotbot', 'petalbot', 'bytespider', 'uptimerobot', 'statuscake', 'pingdom', 'gtmetrix', 'pagespeed', 'lighthouse', 'headlesschrome', 'phantomjs', 'python-requests', 'curl/', 'wget/', 'httpclient', ); foreach ($patterns as $pattern) { if (false !== strpos($user_agent, $pattern)) { return true; } } return false; } /** * Raw source data for the temporary request debug table. * * @return array */ private function debug_source_data() { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Temporary request diagnostics. $utm_source = isset($_GET['utm_source']) ? (string) wp_unslash($_GET['utm_source']) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Temporary request diagnostics. $utm_medium = isset($_GET['utm_medium']) ? (string) wp_unslash($_GET['utm_medium']) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Temporary request diagnostics. $utm_campaign = isset($_GET['utm_campaign']) ? (string) wp_unslash($_GET['utm_campaign']) : ''; $source_hint = $this->source_hint_from_request(false); $full_referrer = isset($_SERVER['HTTP_REFERER']) ? (string) wp_unslash($_SERVER['HTTP_REFERER']) : ''; $referrer_host = $full_referrer ? wp_parse_url($full_referrer, PHP_URL_HOST) : ''; $referrer_host = is_string($referrer_host) ? $referrer_host : ''; $request_path = isset($_SERVER['REQUEST_URI']) ? (string) wp_unslash($_SERVER['REQUEST_URI']) : ''; $classify_host = strtolower($referrer_host); if ($this->is_google_business_profile_visit($classify_host, $full_referrer, $request_path, $utm_source, $utm_medium, $utm_campaign, $source_hint)) { $source = 'google_business_profile'; } elseif ($classify_host) { $source = $this->classify_referrer($classify_host, $full_referrer); } elseif ($utm_source) { $source = $this->classify_source_value($utm_source); } else { $source = 'direct'; } return array( 'source' => $source, 'referrer_host' => $referrer_host, 'referrer_url' => $full_referrer, 'full_referrer' => $full_referrer, 'request_path' => $request_path, 'utm_source' => $utm_source, 'utm_medium' => $utm_medium, 'utm_campaign' => $utm_campaign, ); } /** * Source data. * * @return array */ private function source_data() { $settings = A360_Insights_Settings::get(); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Public read-only UTM tracking parameter. $utm_source = isset($_GET['utm_source']) && ! empty($settings['store_utm_parameters']) ? sanitize_text_field(wp_unslash($_GET['utm_source'])) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Public read-only UTM tracking parameter. $utm_medium = isset($_GET['utm_medium']) && ! empty($settings['store_utm_parameters']) ? sanitize_text_field(wp_unslash($_GET['utm_medium'])) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Public read-only UTM tracking parameter. $utm_campaign = isset($_GET['utm_campaign']) && ! empty($settings['store_utm_parameters']) ? sanitize_text_field(wp_unslash($_GET['utm_campaign'])) : ''; $source_hint = $this->source_hint_from_request(true); $full_referrer = isset($_SERVER['HTTP_REFERER']) ? esc_url_raw(wp_unslash($_SERVER['HTTP_REFERER'])) : ''; $referrer_url = ! empty($settings['store_referrer_details']) ? $full_referrer : ''; $referrer_host = $full_referrer ? wp_parse_url($full_referrer, PHP_URL_HOST) : ''; $referrer_host = is_string($referrer_host) ? strtolower(sanitize_text_field($referrer_host)) : ''; $request_path = isset($_SERVER['REQUEST_URI']) ? sanitize_text_field(wp_unslash($_SERVER['REQUEST_URI'])) : ''; if ($this->is_google_business_profile_visit($referrer_host, $full_referrer, $request_path, $utm_source, $utm_medium, $utm_campaign, $source_hint)) { $source = 'google_business_profile'; } elseif ($referrer_host) { $source = $this->classify_referrer($referrer_host, $referrer_url); } elseif ($utm_source) { $source = $this->classify_source_value($utm_source); } else { $source = 'direct'; } if ('internal' === $source) { $source = 'direct'; $referrer_host = ''; $referrer_url = ''; } return array( 'source' => $source, 'referrer_host' => $referrer_host, 'referrer_url' => $referrer_url, 'full_referrer' => $full_referrer, 'request_path' => $request_path, 'utm_source' => $utm_source, 'utm_medium' => $utm_medium, 'utm_campaign' => $utm_campaign, ); } /** * Build source data from browser-provided page URL and document.referrer. * * @param string $referrer_url Browser document.referrer. * @param string $current_url Current page URL. * @param string $landing_url Session landing URL. * @return array */ private function source_data_from_browser($referrer_url, $current_url, $landing_url) { $settings = A360_Insights_Settings::get(); $current_url = esc_url_raw($current_url); $landing_url = esc_url_raw($landing_url ?: $current_url); $referrer_url = esc_url_raw($referrer_url); $query_vars = array(); $query = $current_url ? wp_parse_url($current_url, PHP_URL_QUERY) : ''; if (is_string($query) && '' !== $query) { parse_str($query, $query_vars); } $utm_source = ! empty($settings['store_utm_parameters']) && isset($query_vars['utm_source']) ? sanitize_text_field($query_vars['utm_source']) : ''; $utm_medium = ! empty($settings['store_utm_parameters']) && isset($query_vars['utm_medium']) ? sanitize_text_field($query_vars['utm_medium']) : ''; $utm_campaign = ! empty($settings['store_utm_parameters']) && isset($query_vars['utm_campaign']) ? sanitize_text_field($query_vars['utm_campaign']) : ''; $referrer_host = $referrer_url ? wp_parse_url($referrer_url, PHP_URL_HOST) : ''; $referrer_host = is_string($referrer_host) ? strtolower(sanitize_text_field($referrer_host)) : ''; $landing_path = $landing_url ? wp_parse_url($landing_url, PHP_URL_PATH) : ''; $landing_path = is_string($landing_path) ? sanitize_text_field($landing_path) : ''; $current_path = $current_url ? wp_parse_url($current_url, PHP_URL_PATH) : ''; $current_path = is_string($current_path) ? sanitize_text_field($current_path) : ''; $source_hint = $this->source_hint_from_values($query_vars, true); if ($this->is_google_business_profile_visit($referrer_host, $referrer_url, $current_path, $utm_source, $utm_medium, $utm_campaign, $source_hint)) { $source = 'google_business_profile'; } elseif ($referrer_host) { $source = $this->classify_referrer($referrer_host, $referrer_url); } elseif ($utm_source) { $source = $this->classify_source_value($utm_source); } else { $source = 'direct'; } if ('internal' === $source) { $source = 'direct'; $referrer_host = ''; $referrer_url = ''; } return array( 'source' => $source, 'referrer_host' => $referrer_host, 'referrer_url' => $referrer_url, 'landing_path' => $landing_path, 'utm_source' => $utm_source, 'utm_medium' => $utm_medium, 'utm_campaign' => $utm_campaign, ); } /** * Get explicit source hint from public request parameters. * * @param bool $sanitize Whether to sanitize for stored tracking data. * @return string */ private function source_hint_from_request($sanitize = true) { return $this->source_hint_from_values($_GET, $sanitize); } /** * Get explicit source hint from query-like values. * * @param array $values Query values. * @param bool $sanitize Whether to sanitize for stored tracking data. * @return string */ private function source_hint_from_values(array $values, $sanitize = true) { $markers = array( 'gmb', 'gbp', 'google_business_profile', 'google-business-profile', 'google_my_business', 'google-my-business', ); foreach ($values as $key => $value) { $key_haystack = strtolower((string) wp_unslash($key)); $value = is_array($value) ? implode(' ', $value) : $value; $value_haystack = strtolower((string) wp_unslash($value)); foreach ($markers as $marker) { if (false !== strpos($key_haystack, $marker) || false !== strpos($value_haystack, $marker)) { return $sanitize ? sanitize_key($marker) : $marker; } } } return ''; } /** * Detect likely Google Business Profile / Maps / local pack visits. * * @param string $host Referrer host. * @param string $url Full referrer URL. * @param string $request_path Current request path. * @param string $utm_source UTM source. * @param string $utm_medium UTM medium. * @param string $utm_campaign UTM campaign. * @param string $source_hint Explicit source hint. * @return bool */ private function is_google_business_profile_visit($host, $url, $request_path = '', $utm_source = '', $utm_medium = '', $utm_campaign = '', $source_hint = '') { $haystack = strtolower( implode( ' ', array( (string) $host, (string) $url, (string) $utm_source, (string) $utm_medium, (string) $utm_campaign, (string) $source_hint, ) ) ); if ( false !== strpos($haystack, 'google_business_profile') || false !== strpos($haystack, 'google-business-profile') || false !== strpos($haystack, 'business_profile') || false !== strpos($haystack, 'business-profile') || false !== strpos($haystack, 'google-my-business') || false !== strpos($haystack, 'google_my_business') || false !== strpos($haystack, 'googleprofile') || false !== strpos($haystack, 'gmb') || false !== strpos($haystack, 'gbp') || 'gbp' === $source_hint || 'gmb' === $source_hint ) { return true; } $normalized_host = strtolower(preg_replace('/^www\./', '', (string) $host)); if (! preg_match('/(^|\.)google\./', $normalized_host) && ! in_array($normalized_host, array('maps.app.goo.gl', 'posts.gle'), true)) { return false; } $path = $url ? wp_parse_url($url, PHP_URL_PATH) : ''; $query = $url ? wp_parse_url($url, PHP_URL_QUERY) : ''; $path = is_string($path) ? strtolower($path) : ''; $query = is_string($query) ? strtolower($query) : ''; if ('maps.google.com' === $normalized_host || in_array($normalized_host, array('maps.app.goo.gl', 'posts.gle'), true)) { return true; } $local_path_markers = array( '/maps', '/local', '/place', '/business', '/localservices', ); foreach ($local_path_markers as $marker) { if (false !== strpos($path, $marker)) { return true; } } $local_query_markers = array( 'tbm=lcl', 'ludocid=', 'kgmid=', 'lrd=', 'rlst=', 'stick=', ); foreach ($local_query_markers as $marker) { if (false !== strpos($query, $marker)) { return true; } } return false; } private function classify_source_value($value) { $value = strtolower(sanitize_text_field($value)); if (false !== strpos($value, 'codex')) { return 'codex'; } if (false !== strpos($value, 'chatgpt') || false !== strpos($value, 'openai')) { return 'chatgpt'; } if (false !== strpos($value, 'gemini') || false !== strpos($value, 'bard')) { return 'gemini'; } if (false !== strpos($value, 'copilot')) { return 'copilot'; } if (false !== strpos($value, 'perplexity')) { return 'perplexity'; } if (false !== strpos($value, 'claude') || false !== strpos($value, 'anthropic')) { return 'claude'; } if (false !== strpos($value, 'meta.ai') || false !== strpos($value, 'meta_ai')) { return 'meta_ai'; } if (false !== strpos($value, 'mistral') || false !== strpos($value, 'lechat')) { return 'mistral'; } if (false !== strpos($value, 'you.com') || 'you' === $value) { return 'you'; } if (false !== strpos($value, 'poe')) { return 'poe'; } if (false !== strpos($value, 'phind')) { return 'phind'; } if (false !== strpos($value, 'deepseek')) { return 'deepseek'; } if (false !== strpos($value, 'grok') || false !== strpos($value, 'x.ai')) { return 'grok'; } if (false !== strpos($value, 'google')) { return 'google'; } if (false !== strpos($value, 'bing')) { return 'bing'; } return sanitize_key($value); } /** * Classify referrer host. * * @param string $host Host. * @param string $url Full referrer URL. * @return string */ private function classify_referrer($host, $url = '') { $site_host = wp_parse_url(home_url(), PHP_URL_HOST); $site_host = is_string($site_host) ? strtolower(preg_replace('/^www\./', '', $site_host)) : ''; $host = strtolower(preg_replace('/^www\./', '', $host)); $path = $url ? wp_parse_url($url, PHP_URL_PATH) : ''; $path = is_string($path) ? strtolower($path) : ''; if ( $site_host && ( $host === $site_host || substr($host, -1 * (strlen($site_host) + 1)) === '.' . $site_host ) ) { return 'internal'; } if ( preg_match('/^codex\.openai\.com$/', $host) || ( preg_match('/(^|\.)chatgpt\.com$|(^|\.)openai\.com$/', $host) && false !== strpos($path, 'codex') ) ) { return 'codex'; } if (preg_match('/(^|\.)chatgpt\.com$|(^|\.)openai\.com$/', $host)) { return 'chatgpt'; } if (preg_match('/^gemini\.google\.com$|^bard\.google\.com$/', $host)) { return 'gemini'; } if (preg_match('/^copilot\.microsoft\.com$/', $host)) { return 'copilot'; } if (preg_match('/(^|\.)perplexity\.ai$/', $host)) { return 'perplexity'; } if (preg_match('/(^|\.)claude\.ai$|(^|\.)anthropic\.com$/', $host)) { return 'claude'; } if (preg_match('/(^|\.)meta\.ai$/', $host)) { return 'meta_ai'; } if (preg_match('/(^|\.)mistral\.ai$|(^|\.)chat\.mistral\.ai$/', $host)) { return 'mistral'; } if (preg_match('/(^|\.)you\.com$/', $host)) { return 'you'; } if (preg_match('/(^|\.)poe\.com$/', $host)) { return 'poe'; } if (preg_match('/(^|\.)phind\.com$/', $host)) { return 'phind'; } if (preg_match('/(^|\.)deepseek\.com$/', $host)) { return 'deepseek'; } if (preg_match('/(^|\.)grok\.com$|(^|\.)x\.ai$/', $host)) { return 'grok'; } if (preg_match('/(^|\.)google\./', $host)) { return 'google'; } if (preg_match('/(^|\.)facebook\.com$|(^|\.)fb\.com$|(^|\.)l\.facebook\.com$|(^|\.)m\.facebook\.com$/', $host)) { return 'facebook'; } if (preg_match('/(^|\.)youtube\.com$|(^|\.)youtu\.be$/', $host)) { return 'youtube'; } if (preg_match('/instagram\.com|x\.com|twitter\.com|linkedin\.com|tiktok\.com|pinterest\./', $host)) { return 'social'; } return 'referral'; } }