| @@ -6,9 +6,9 @@ | ||
| 6 | 6 | |
| 7 | 7 | /** |
| 8 | 8 | * Lightweight, non-blocking doc-view collection for the Free Overview. |
| 9 | 9 | * |
| 10 | - * The frontend tracker (assets/public/js/analytics-tracker.js) fires a | |
| 10 | + * The frontend tracker (assets/static/public/js/analytics-tracker.js) fires a | |
| 11 | 11 | * sendBeacon after DOMContentLoaded on single docs; the REST ingest endpoint |
| 12 | 12 | * (REST/AnalyticsTracker) calls record_view() which increments the daily |
| 13 | 13 | * aggregate row in {prefix}betterdocs_analytics plus the per-post views meta. |
| 14 | 14 | * |
| @@ -188,9 +188,15 @@ | ||
| 188 | 188 | return false; |
| 189 | 189 | } |
| 190 | 190 | |
| 191 | 191 | if ( $this->settings->get( 'exclude_bot_analytics', true ) == 1 ) { |
| 192 | - $bots = [ 'google', 'msnbot', 'ia_archiver', 'lycos', 'jeeves', 'scooter', 'fast-webcrawler', 'slurp@inktomi', 'turnitinbot', 'technorati', 'yahoo', 'findexa', 'findlinks', 'gaisbo', 'zyborg', 'surveybot', 'bloglines', 'blogsearch', 'pubsub', 'syndic8', 'userland', 'gigabot', 'become.com', 'baiduspider', '360spider', 'spider', 'sosospider', 'yandex' ]; | |
| 192 | + $bots = [ 'google', 'msnbot', 'ia_archiver', 'lycos', 'jeeves', 'scooter', 'fast-webcrawler', 'slurp@inktomi', 'turnitinbot', 'technorati', 'yahoo', 'findexa', 'findlinks', 'gaisbo', 'zyborg', 'surveybot', 'bloglines', 'blogsearch', 'pubsub', 'syndic8', 'userland', 'gigabot', 'become.com', 'baiduspider', '360spider', 'spider', 'sosospider', 'yandex', | |
| 193 | + // AI agents / crawlers — mirror of the Pro AiTrafficCollector catalog so a | |
| 194 | + // JS-capable or spoofed AI user-agent is never double-counted as a human | |
| 195 | + // view (Pro records it as an AI fetch server-side; the human path is a JS | |
| 196 | + // beacon). Free must not depend on Pro, so the tokens are duplicated here. | |
| 197 | + // stripos is case-insensitive, so lowercase is sufficient. | |
| 198 | + 'gptbot', 'chatgpt-user', 'oai-searchbot', 'claudebot', 'anthropic-ai', 'claude-user', 'claude-web', 'claude-searchbot', 'perplexitybot', 'perplexity-user', 'google-extended', 'googleother', 'applebot-extended', 'cursor/', 'copilot', 'meta-externalagent', 'meta-externalfetcher', 'facebookbot', 'youbot', 'ccbot', 'bytespider', 'duckassistbot' ]; | |
| 193 | 199 | $useragent = isset( $_SERVER['HTTP_USER_AGENT'] ) ? sanitize_text_field( wp_unslash( $_SERVER['HTTP_USER_AGENT'] ) ) : ''; |
| 194 | 200 | if ( $useragent !== '' ) { |
| 195 | 201 | foreach ( $bots as $lookfor ) { |
| 196 | 202 | if ( false !== stripos( $useragent, $lookfor ) ) { |