文章目录
-
- 在当今数字化时代,网站不仅仅是信息展示的平台,更是与用户互动、收集数据、优化体验的重要工具。对于WordPress网站管理员而言,了解访客行为、分析流量来源、优化内容策略是持续成功的关键。虽然市面上有Google Analytics、百度统计等成熟解决方案,但通过WordPress代码二次开发实现自定义统计和小工具集成,能够带来以下独特优势: 数据自主性:完全掌控数据收集、存储和处理流程 深度定制:根据特定业务需求设计统计维度 性能优化:减少对外部服务的依赖,提升页面加载速度 隐私合规:更好地适应GDPR等数据保护法规 成本控制:长期来看可能降低第三方服务费用 本教程将详细指导您如何通过WordPress代码二次开发,实现网站访问统计与流量分析功能,并集成常用互联网小工具,打造一个功能全面、自主可控的网站生态系统。
-
- 在开始二次开发前,需要确保您的环境满足以下条件: WordPress安装:建议使用最新版本的WordPress(5.8+) 本地开发环境:推荐使用Local by Flywheel、XAMPP或MAMP 代码编辑器:VS Code、PHPStorm或Sublime Text 数据库管理工具:phpMyAdmin或Adminer 版本控制系统:Git(可选但推荐)
- 为了避免主题更新导致代码丢失,我们将通过创建独立插件的方式实现功能: <?php /** * Plugin Name: 自定义网站统计与小工具套件 * Plugin URI: https://yourwebsite.com/ * Description: 自定义网站访问统计、流量分析及常用小工具集成 * Version: 1.0.0 * Author: 您的名称 * License: GPL v2 or later */ // 防止直接访问 if (!defined('ABSPATH')) { exit; } // 定义插件常量 define('CUSTOM_STATS_VERSION', '1.0.0'); define('CUSTOM_STATS_PLUGIN_DIR', plugin_dir_path(__FILE__)); define('CUSTOM_STATS_PLUGIN_URL', plugin_dir_url(__FILE__)); // 初始化插件 require_once CUSTOM_STATS_PLUGIN_DIR . 'includes/class-core.php'; require_once CUSTOM_STATS_PLUGIN_DIR . 'includes/class-database.php'; require_once CUSTOM_STATS_PLUGIN_DIR . 'includes/class-tracker.php'; // 启动插件 function custom_stats_init() { $core = new Custom_Stats_Core(); $core->run(); } add_action('plugins_loaded', 'custom_stats_init');
- 创建专门的数据表来存储访问统计信息: // includes/class-database.php class Custom_Stats_Database { public function create_tables() { global $wpdb; $charset_collate = $wpdb->get_charset_collate(); $table_name = $wpdb->prefix . 'custom_visits'; $sql = "CREATE TABLE IF NOT EXISTS $table_name ( id bigint(20) NOT NULL AUTO_INCREMENT, session_id varchar(64) NOT NULL, user_id bigint(20) DEFAULT NULL, ip_address varchar(45) DEFAULT NULL, user_agent text, referrer text, landing_page varchar(512) NOT NULL, exit_page varchar(512) DEFAULT NULL, page_views int(11) DEFAULT 1, visit_duration int(11) DEFAULT 0, country_code varchar(2) DEFAULT NULL, city varchar(100) DEFAULT NULL, device_type varchar(20) DEFAULT NULL, browser varchar(50) DEFAULT NULL, os varchar(50) DEFAULT NULL, screen_resolution varchar(20) DEFAULT NULL, is_new_visit tinyint(1) DEFAULT 1, created_at datetime DEFAULT CURRENT_TIMESTAMP, updated_at datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY session_id (session_id), KEY user_id (user_id), KEY created_at (created_at), KEY country_code (country_code), KEY device_type (device_type) ) $charset_collate;"; require_once(ABSPATH . 'wp-admin/includes/upgrade.php'); dbDelta($sql); // 创建页面访问详情表 $page_views_table = $wpdb->prefix . 'custom_page_views'; $sql2 = "CREATE TABLE IF NOT EXISTS $page_views_table ( id bigint(20) NOT NULL AUTO_INCREMENT, visit_id bigint(20) NOT NULL, page_url varchar(512) NOT NULL, page_title varchar(255) DEFAULT NULL, time_on_page int(11) DEFAULT 0, scroll_depth int(3) DEFAULT 0, created_at datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY visit_id (visit_id), KEY page_url (page_url(191)) ) $charset_collate;"; dbDelta($sql2); } public function update_tables() { // 未来版本更新时修改表结构 } }
-
- 创建主追踪器类,负责收集和存储访问数据: // includes/class-tracker.php class Custom_Stats_Tracker { private $db; private $session_id; private $current_visit_id; public function __construct() { global $wpdb; $this->db = $wpdb; $this->init_session(); } private function init_session() { if (!session_id()) { session_start(); } if (!isset($_SESSION['custom_stats_session_id'])) { $_SESSION['custom_stats_session_id'] = $this->generate_session_id(); } $this->session_id = $_SESSION['custom_stats_session_id']; } private function generate_session_id() { return md5(uniqid(mt_rand(), true) . $_SERVER['REMOTE_ADDR'] . $_SERVER['HTTP_USER_AGENT']); } public function track_visit() { // 检查是否为机器人或排除的IP if ($this->is_excluded()) { return; } $current_url = $this->get_current_url(); $referrer = $this->get_referrer(); // 检查是否为新访问 $is_new_visit = $this->is_new_visit(); if ($is_new_visit) { $this->current_visit_id = $this->record_new_visit($current_url, $referrer); } else { $this->update_existing_visit($current_url); } // 记录页面浏览详情 $this->record_page_view($current_url); // 设置JavaScript变量用于前端追踪 $this->set_frontend_data(); } private function is_excluded() { $excluded_ips = get_option('custom_stats_excluded_ips', []); $current_ip = $this->get_client_ip(); // 检查IP是否在排除列表中 if (in_array($current_ip, $excluded_ips)) { return true; } // 检查是否为搜索引擎机器人 $user_agent = $_SERVER['HTTP_USER_AGENT'] ?? ''; $bots = ['bot', 'crawl', 'spider', 'slurp', 'search', 'archiver']; foreach ($bots as $bot) { if (stripos($user_agent, $bot) !== false) { return true; } } return false; } private function get_client_ip() { $ip_keys = ['HTTP_CLIENT_IP', 'HTTP_X_FORWARDED_FOR', 'HTTP_X_FORWARDED', 'HTTP_X_CLUSTER_CLIENT_IP', 'HTTP_FORWARDED_FOR', 'HTTP_FORWARDED', 'REMOTE_ADDR']; foreach ($ip_keys as $key) { if (array_key_exists($key, $_SERVER) === true) { foreach (explode(',', $_SERVER[$key]) as $ip) { $ip = trim($ip); if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) !== false) { return $ip; } } } } return $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0'; } private function get_current_url() { $protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? "https" : "http"; return $protocol . "://" . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']; } private function get_referrer() { return $_SERVER['HTTP_REFERER'] ?? ''; } private function is_new_visit() { $table_name = $this->db->prefix . 'custom_visits'; $query = $this->db->prepare( "SELECT id FROM $table_name WHERE session_id = %s AND DATE(created_at) = CURDATE() ORDER BY created_at DESC LIMIT 1", $this->session_id ); $result = $this->db->get_var($query); return empty($result); } private function record_new_visit($url, $referrer) { $table_name = $this->db->prefix . 'custom_visits'; // 获取地理位置信息(简化版,实际应使用IP数据库) $geo_info = $this->get_geo_info(); // 解析用户代理 $device_info = $this->parse_user_agent(); $data = [ 'session_id' => $this->session_id, 'user_id' => get_current_user_id() ?: null, 'ip_address' => $this->get_client_ip(), 'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? '', 'referrer' => $referrer, 'landing_page' => $url, 'country_code' => $geo_info['country_code'], 'city' => $geo_info['city'], 'device_type' => $device_info['device_type'], 'browser' => $device_info['browser'], 'os' => $device_info['os'], 'screen_resolution' => $this->get_screen_resolution(), 'is_new_visit' => 1, 'created_at' => current_time('mysql') ]; $this->db->insert($table_name, $data); return $this->db->insert_id; } private function get_geo_info() { // 简化版,实际应集成MaxMind GeoIP或类似服务 $ip = $this->get_client_ip(); // 本地IP返回空信息 if ($ip === '127.0.0.1' || strpos($ip, '192.168.') === 0) { return ['country_code' => null, 'city' => null]; } // 这里可以调用第三方API或本地数据库 // 示例:使用ipapi.co(免费版有限制) return ['country_code' => null, 'city' => null]; } private function parse_user_agent() { $user_agent = $_SERVER['HTTP_USER_AGENT'] ?? ''; // 设备类型检测 $device_type = 'desktop'; if (preg_match('/(android|webos|iphone|ipad|ipod|blackberry|windows phone)/i', $user_agent)) { $device_type = 'mobile'; } elseif (preg_match('/(tablet|ipad|playbook|silk)/i', $user_agent)) { $device_type = 'tablet'; } // 浏览器检测 $browser = 'Unknown'; if (preg_match('/MSIE|Trident/i', $user_agent)) { $browser = 'Internet Explorer'; } elseif (preg_match('/Firefox/i', $user_agent)) { $browser = 'Firefox'; } elseif (preg_match('/Chrome/i', $user_agent)) { $browser = 'Chrome'; } elseif (preg_match('/Safari/i', $user_agent)) { $browser = 'Safari'; } elseif (preg_match('/Edge/i', $user_agent)) { $browser = 'Edge'; } elseif (preg_match('/Opera|OPR/i', $user_agent)) { $browser = 'Opera'; } // 操作系统检测 $os = 'Unknown'; if (preg_match('/Windows NT 10.0/i', $user_agent)) { $os = 'Windows 10'; } elseif (preg_match('/Windows NT 6.3/i', $user_agent)) { $os = 'Windows 8.1'; } elseif (preg_match('/Windows NT 6.2/i', $user_agent)) { $os = 'Windows 8'; } elseif (preg_match('/Windows NT 6.1/i', $user_agent)) { $os = 'Windows 7'; } elseif (preg_match('/Macintosh|Mac OS X/i', $user_agent)) { $os = 'macOS'; } elseif (preg_match('/Linux/i', $user_agent)) { $os = 'Linux'; } elseif (preg_match('/Android/i', $user_agent)) { $os = 'Android'; } elseif (preg_match('/iPhone|iPad|iPod/i', $user_agent)) { $os = 'iOS'; } return [ 'device_type' => $device_type, 'browser' => $browser, 'os' => $os ]; } private function get_screen_resolution() { // 通过JavaScript获取,这里先返回空值 return ''; } private function set_frontend_data() { add_action('wp_footer', function() { ?> <script> window.customStats = { sessionId: '<?php echo esc_js($this->session_id); ?>', visitId: <?php echo esc_js($this->current_visit_id); ?>, nonce: '<?php echo wp_create_nonce('custom_stats_nonce'); ?>', ajaxUrl: '<?php echo admin_url('admin-ajax.php'); ?>' }; </script> <?php }); } }
- 创建前端JavaScript文件,用于收集客户端数据: // assets/js/frontend-tracker.js (function() { 'use strict'; class FrontendTracker { constructor() { this.config = window.customStats || {}; this.pageStartTime = Date.now(); this.maxScrollDepth = 0; this.init(); } init() { this.trackPageView(); this.trackScrollDepth(); this.trackTimeOnPage(); this.trackClicks(); this.trackFormSubmissions(); this.setupBeforeUnload(); } trackPageView() { const data = { action: 'custom_stats_track_pageview', nonce: this.config.nonce, visit_id: this.config.visitId, page_url: window.location.href, page_title: document.title, screen_resolution: this.getScreenResolution(), viewport_size: this.getViewportSize() }; this.sendRequest(data); } trackScrollDepth() { let scrollCheckTimer; const checkScrollDepth = () => { const scrollTop = window.pageYOffset || document.documentElement.scrollTop; const scrollHeight = document.documentElement.scrollHeight - document.documentElement.clientHeight; const scrollPercentage = scrollHeight > 0 ? Math.round((scrollTop / scrollHeight) * 100) : 0; if (scrollPercentage > this.maxScrollDepth) { this.maxScrollDepth = scrollPercentage; // 记录25%、50%、75%、100%的关键点 if ([25, 50, 75, 100].includes(scrollPercentage)) { const data = { action: 'custom_stats_track_scroll', nonce: this.config.nonce, visit_id: this.config.visitId, scroll_depth: scrollPercentage, page_url: window.location.href }; this.sendRequest(data); } } }; window.addEventListener('scroll', () => { clearTimeout(scrollCheckTimer); scrollCheckTimer = setTimeout(checkScrollDepth, 100); }); } trackTimeOnPage() { // 定期发送时间更新 setInterval(() => { const timeOnPage = Math.round((Date.now() - this.pageStartTime) / 1000); const data = { action: 'custom_stats_update_time', nonce: this.config.nonce, visit_id: this.config.visitId, time_on_page: timeOnPage }; this.sendRequest(data); }, 30000); // 每30秒发送一次 } trackClicks() { document.addEventListener('click', (e) => { const target = e.target; const link = target.closest('a'); if (link && link.href) { const data = { action: 'custom_stats_track_click', nonce: this.config.nonce, visit_id: this.config.visitId, link_url: link.href, link_text: link.textContent.substring(0, 100), page_url: window.location.href };
- 继续前端JavaScript代码: // 如果是外部链接,立即发送数据 if (this.isExternalLink(link.href)) { this.sendRequest(data, true); // 同步发送 } else { this.sendRequest(data); } } }); } trackFormSubmissions() { document.addEventListener('submit', (e) => { const form = e.target; const formId = form.id || form.name || 'unknown'; const data = { action: 'custom_stats_track_form', nonce: this.config.nonce, visit_id: this.config.visitId, form_id: formId, form_action: form.action, page_url: window.location.href }; this.sendRequest(data); }); } setupBeforeUnload() { window.addEventListener('beforeunload', () => { const timeOnPage = Math.round((Date.now() - this.pageStartTime) / 1000); const data = { action: 'custom_stats_track_exit', nonce: this.config.nonce, visit_id: this.config.visitId, time_on_page: timeOnPage, scroll_depth: this.maxScrollDepth, exit_page: window.location.href }; // 使用navigator.sendBeacon进行可靠的离开页面数据发送 this.sendBeacon(data); }); } sendRequest(data, sync = false) { const formData = new FormData(); for (const key in data) { formData.append(key, data[key]); } if (sync) { // 同步请求(用于离开页面时) const xhr = new XMLHttpRequest(); xhr.open('POST', this.config.ajaxUrl, false); xhr.send(formData); } else { // 异步请求 fetch(this.config.ajaxUrl, { method: 'POST', body: formData, keepalive: true // 允许在页面卸载后继续发送 }).catch(error => { console.error('Tracking error:', error); }); } } sendBeacon(data) { const blob = new Blob([JSON.stringify(data)], {type: 'application/json'}); navigator.sendBeacon(this.config.ajaxUrl + '?action=custom_stats_track_exit', blob); } getScreenResolution() { return window.screen.width + 'x' + window.screen.height; } getViewportSize() { return window.innerWidth + 'x' + window.innerHeight; } isExternalLink(url) { const currentHost = window.location.hostname; const linkHost = (new URL(url, window.location.href)).hostname; return linkHost !== currentHost && linkHost !== ''; } } // 初始化追踪器 document.addEventListener('DOMContentLoaded', () => { if (window.customStats) { new FrontendTracker(); } }); })();
- 创建AJAX请求处理类: // includes/class-ajax-handler.php class Custom_Stats_Ajax_Handler { private $db; public function __construct() { global $wpdb; $this->db = $wpdb; $this->register_ajax_actions(); } private function register_ajax_actions() { // 页面浏览追踪 add_action('wp_ajax_custom_stats_track_pageview', [$this, 'handle_pageview']); add_action('wp_ajax_nopriv_custom_stats_track_pageview', [$this, 'handle_pageview']); // 滚动深度追踪 add_action('wp_ajax_custom_stats_track_scroll', [$this, 'handle_scroll']); add_action('wp_ajax_nopriv_custom_stats_track_scroll', [$this, 'handle_scroll']); // 点击追踪 add_action('wp_ajax_custom_stats_track_click', [$this, 'handle_click']); add_action('wp_ajax_nopriv_custom_stats_track_click', [$this, 'handle_click']); // 表单提交追踪 add_action('wp_ajax_custom_stats_track_form', [$this, 'handle_form']); add_action('wp_ajax_nopriv_custom_stats_track_form', [$this, 'handle_form']); // 退出页面追踪 add_action('wp_ajax_custom_stats_track_exit', [$this, 'handle_exit']); add_action('wp_ajax_nopriv_custom_stats_track_exit', [$this, 'handle_exit']); // 时间更新 add_action('wp_ajax_custom_stats_update_time', [$this, 'update_time']); add_action('wp_ajax_nopriv_custom_stats_update_time', [$this, 'update_time']); } public function handle_pageview() { $this->verify_nonce(); $visit_id = intval($_POST['visit_id']); $page_url = sanitize_text_field($_POST['page_url']); $page_title = sanitize_text_field($_POST['page_title']); $screen_resolution = sanitize_text_field($_POST['screen_resolution']); $table_name = $this->db->prefix . 'custom_page_views'; $data = [ 'visit_id' => $visit_id, 'page_url' => $page_url, 'page_title' => $page_title, 'created_at' => current_time('mysql') ]; // 更新访问记录中的屏幕分辨率 if (!empty($screen_resolution)) { $visits_table = $this->db->prefix . 'custom_visits'; $this->db->update( $visits_table, ['screen_resolution' => $screen_resolution], ['id' => $visit_id] ); } $this->db->insert($table_name, $data); wp_die('1'); } public function handle_scroll() { $this->verify_nonce(); $visit_id = intval($_POST['visit_id']); $scroll_depth = intval($_POST['scroll_depth']); $page_url = sanitize_text_field($_POST['page_url']); $table_name = $this->db->prefix . 'custom_page_views'; // 找到当前页面的最新记录并更新滚动深度 $this->db->query( $this->db->prepare( "UPDATE $table_name SET scroll_depth = %d WHERE visit_id = %d AND page_url = %s ORDER BY created_at DESC LIMIT 1", $scroll_depth, $visit_id, $page_url ) ); wp_die('1'); } public function handle_click() { $this->verify_nonce(); $visit_id = intval($_POST['visit_id']); $link_url = esc_url_raw($_POST['link_url']); $link_text = sanitize_text_field($_POST['link_text']); $page_url = sanitize_text_field($_POST['page_url']); $table_name = $this->db->prefix . 'custom_clicks'; // 创建点击记录表(如果不存在) $this->create_clicks_table(); $data = [ 'visit_id' => $visit_id, 'link_url' => $link_url, 'link_text' => $link_text, 'page_url' => $page_url, 'created_at' => current_time('mysql') ]; $this->db->insert($table_name, $data); wp_die('1'); } private function create_clicks_table() { $table_name = $this->db->prefix . 'custom_clicks'; if ($this->db->get_var("SHOW TABLES LIKE '$table_name'") != $table_name) { $charset_collate = $this->db->get_charset_collate(); $sql = "CREATE TABLE $table_name ( id bigint(20) NOT NULL AUTO_INCREMENT, visit_id bigint(20) NOT NULL, link_url varchar(512) NOT NULL, link_text varchar(255) DEFAULT NULL, page_url varchar(512) NOT NULL, created_at datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY visit_id (visit_id), KEY link_url (link_url(191)) ) $charset_collate;"; require_once(ABSPATH . 'wp-admin/includes/upgrade.php'); dbDelta($sql); } } public function handle_form() { $this->verify_nonce(); $visit_id = intval($_POST['visit_id']); $form_id = sanitize_text_field($_POST['form_id']); $form_action = esc_url_raw($_POST['form_action']); $page_url = sanitize_text_field($_POST['page_url']); $table_name = $this->db->prefix . 'custom_form_submissions'; // 创建表单提交表(如果不存在) $this->create_forms_table(); $data = [ 'visit_id' => $visit_id, 'form_id' => $form_id, 'form_action' => $form_action, 'page_url' => $page_url, 'created_at' => current_time('mysql') ]; $this->db->insert($table_name, $data); wp_die('1'); } private function create_forms_table() { $table_name = $this->db->prefix . 'custom_form_submissions'; if ($this->db->get_var("SHOW TABLES LIKE '$table_name'") != $table_name) { $charset_collate = $this->db->get_charset_collate(); $sql = "CREATE TABLE $table_name ( id bigint(20) NOT NULL AUTO_INCREMENT, visit_id bigint(20) NOT NULL, form_id varchar(100) NOT NULL, form_action varchar(512) NOT NULL, page_url varchar(512) NOT NULL, created_at datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY visit_id (visit_id), KEY form_id (form_id) ) $charset_collate;"; require_once(ABSPATH . 'wp-admin/includes/upgrade.php'); dbDelta($sql); } } public function handle_exit() { // 对于sendBeacon请求,数据在php://input中 if ($_SERVER['REQUEST_METHOD'] === 'POST' && empty($_POST)) { $input = file_get_contents('php://input'); $data = json_decode($input, true); if ($data) { $_POST = $data; } } $visit_id = intval($_POST['visit_id']); $time_on_page = intval($_POST['time_on_page']); $scroll_depth = intval($_POST['scroll_depth']); $exit_page = sanitize_text_field($_POST['exit_page']); $table_name = $this->db->prefix . 'custom_visits'; $this->db->update( $table_name, [ 'exit_page' => $exit_page, 'visit_duration' => $time_on_page, 'updated_at' => current_time('mysql') ], ['id' => $visit_id] ); // 更新最后页面的滚动深度 $page_views_table = $this->db->prefix . 'custom_page_views'; $this->db->query( $this->db->prepare( "UPDATE $page_views_table SET scroll_depth = %d WHERE visit_id = %d ORDER BY created_at DESC LIMIT 1", $scroll_depth, $visit_id ) ); wp_die('1'); } public function update_time() { $this->verify_nonce(); $visit_id = intval($_POST['visit_id']); $time_on_page = intval($_POST['time_on_page']); $table_name = $this->db->prefix . 'custom_visits'; $this->db->update( $table_name, [ 'visit_duration' => $time_on_page, 'updated_at' => current_time('mysql') ], ['id' => $visit_id] ); wp_die('1'); } private function verify_nonce() { if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'custom_stats_nonce')) { wp_die('Security check failed', 403); } } }
在当今数字化时代,网站不仅仅是信息展示的平台,更是与用户互动、收集数据、优化体验的重要工具。对于WordPress网站管理员而言,了解访客行为、分析流量来源、优化内容策略是持续成功的关键。虽然市面上有Google Analytics、百度统计等成熟解决方案,但通过WordPress代码二次开发实现自定义统计和小工具集成,能够带来以下独特优势:
- 数据自主性:完全掌控数据收集、存储和处理流程
- 深度定制:根据特定业务需求设计统计维度
- 性能优化:减少对外部服务的依赖,提升页面加载速度
- 隐私合规:更好地适应GDPR等数据保护法规
- 成本控制:长期来看可能降低第三方服务费用
本教程将详细指导您如何通过WordPress代码二次开发,实现网站访问统计与流量分析功能,并集成常用互联网小工具,打造一个功能全面、自主可控的网站生态系统。
在开始二次开发前,需要确保您的环境满足以下条件:
- WordPress安装:建议使用最新版本的WordPress(5.8+)
- 本地开发环境:推荐使用Local by Flywheel、XAMPP或MAMP
- 代码编辑器:VS Code、PHPStorm或Sublime Text
- 数据库管理工具:phpMyAdmin或Adminer
- 版本控制系统:Git(可选但推荐)
为了避免主题更新导致代码丢失,我们将通过创建独立插件的方式实现功能:
<?php
/**
* Plugin Name: 自定义网站统计与小工具套件
* Plugin URI: https://yourwebsite.com/
* Description: 自定义网站访问统计、流量分析及常用小工具集成
* Version: 1.0.0
* Author: 您的名称
* License: GPL v2 or later
*/
// 防止直接访问
if (!defined('ABSPATH')) {
exit;
}
// 定义插件常量
define('CUSTOM_STATS_VERSION', '1.0.0');
define('CUSTOM_STATS_PLUGIN_DIR', plugin_dir_path(__FILE__));
define('CUSTOM_STATS_PLUGIN_URL', plugin_dir_url(__FILE__));
// 初始化插件
require_once CUSTOM_STATS_PLUGIN_DIR . 'includes/class-core.php';
require_once CUSTOM_STATS_PLUGIN_DIR . 'includes/class-database.php';
require_once CUSTOM_STATS_PLUGIN_DIR . 'includes/class-tracker.php';
// 启动插件
function custom_stats_init() {
$core = new Custom_Stats_Core();
$core->run();
}
add_action('plugins_loaded', 'custom_stats_init');
创建专门的数据表来存储访问统计信息:
// includes/class-database.php
class Custom_Stats_Database {
public function create_tables() {
global $wpdb;
$charset_collate = $wpdb->get_charset_collate();
$table_name = $wpdb->prefix . 'custom_visits';
$sql = "CREATE TABLE IF NOT EXISTS $table_name (
id bigint(20) NOT NULL AUTO_INCREMENT,
session_id varchar(64) NOT NULL,
user_id bigint(20) DEFAULT NULL,
ip_address varchar(45) DEFAULT NULL,
user_agent text,
referrer text,
landing_page varchar(512) NOT NULL,
exit_page varchar(512) DEFAULT NULL,
page_views int(11) DEFAULT 1,
visit_duration int(11) DEFAULT 0,
country_code varchar(2) DEFAULT NULL,
city varchar(100) DEFAULT NULL,
device_type varchar(20) DEFAULT NULL,
browser varchar(50) DEFAULT NULL,
os varchar(50) DEFAULT NULL,
screen_resolution varchar(20) DEFAULT NULL,
is_new_visit tinyint(1) DEFAULT 1,
created_at datetime DEFAULT CURRENT_TIMESTAMP,
updated_at datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id),
KEY session_id (session_id),
KEY user_id (user_id),
KEY created_at (created_at),
KEY country_code (country_code),
KEY device_type (device_type)
) $charset_collate;";
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
dbDelta($sql);
// 创建页面访问详情表
$page_views_table = $wpdb->prefix . 'custom_page_views';
$sql2 = "CREATE TABLE IF NOT EXISTS $page_views_table (
id bigint(20) NOT NULL AUTO_INCREMENT,
visit_id bigint(20) NOT NULL,
page_url varchar(512) NOT NULL,
page_title varchar(255) DEFAULT NULL,
time_on_page int(11) DEFAULT 0,
scroll_depth int(3) DEFAULT 0,
created_at datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id),
KEY visit_id (visit_id),
KEY page_url (page_url(191))
) $charset_collate;";
dbDelta($sql2);
}
public function update_tables() {
// 未来版本更新时修改表结构
}
}
创建主追踪器类,负责收集和存储访问数据:
// includes/class-tracker.php
class Custom_Stats_Tracker {
private $db;
private $session_id;
private $current_visit_id;
public function __construct() {
global $wpdb;
$this->db = $wpdb;
$this->init_session();
}
private function init_session() {
if (!session_id()) {
session_start();
}
if (!isset($_SESSION['custom_stats_session_id'])) {
$_SESSION['custom_stats_session_id'] = $this->generate_session_id();
}
$this->session_id = $_SESSION['custom_stats_session_id'];
}
private function generate_session_id() {
return md5(uniqid(mt_rand(), true) . $_SERVER['REMOTE_ADDR'] . $_SERVER['HTTP_USER_AGENT']);
}
public function track_visit() {
// 检查是否为机器人或排除的IP
if ($this->is_excluded()) {
return;
}
$current_url = $this->get_current_url();
$referrer = $this->get_referrer();
// 检查是否为新访问
$is_new_visit = $this->is_new_visit();
if ($is_new_visit) {
$this->current_visit_id = $this->record_new_visit($current_url, $referrer);
} else {
$this->update_existing_visit($current_url);
}
// 记录页面浏览详情
$this->record_page_view($current_url);
// 设置JavaScript变量用于前端追踪
$this->set_frontend_data();
}
private function is_excluded() {
$excluded_ips = get_option('custom_stats_excluded_ips', []);
$current_ip = $this->get_client_ip();
// 检查IP是否在排除列表中
if (in_array($current_ip, $excluded_ips)) {
return true;
}
// 检查是否为搜索引擎机器人
$user_agent = $_SERVER['HTTP_USER_AGENT'] ?? '';
$bots = ['bot', 'crawl', 'spider', 'slurp', 'search', 'archiver'];
foreach ($bots as $bot) {
if (stripos($user_agent, $bot) !== false) {
return true;
}
}
return false;
}
private function get_client_ip() {
$ip_keys = ['HTTP_CLIENT_IP', 'HTTP_X_FORWARDED_FOR', 'HTTP_X_FORWARDED',
'HTTP_X_CLUSTER_CLIENT_IP', 'HTTP_FORWARDED_FOR', 'HTTP_FORWARDED',
'REMOTE_ADDR'];
foreach ($ip_keys as $key) {
if (array_key_exists($key, $_SERVER) === true) {
foreach (explode(',', $_SERVER[$key]) as $ip) {
$ip = trim($ip);
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) !== false) {
return $ip;
}
}
}
}
return $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0';
}
private function get_current_url() {
$protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? "https" : "http";
return $protocol . "://" . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
}
private function get_referrer() {
return $_SERVER['HTTP_REFERER'] ?? '';
}
private function is_new_visit() {
$table_name = $this->db->prefix . 'custom_visits';
$query = $this->db->prepare(
"SELECT id FROM $table_name
WHERE session_id = %s
AND DATE(created_at) = CURDATE()
ORDER BY created_at DESC
LIMIT 1",
$this->session_id
);
$result = $this->db->get_var($query);
return empty($result);
}
private function record_new_visit($url, $referrer) {
$table_name = $this->db->prefix . 'custom_visits';
// 获取地理位置信息(简化版,实际应使用IP数据库)
$geo_info = $this->get_geo_info();
// 解析用户代理
$device_info = $this->parse_user_agent();
$data = [
'session_id' => $this->session_id,
'user_id' => get_current_user_id() ?: null,
'ip_address' => $this->get_client_ip(),
'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? '',
'referrer' => $referrer,
'landing_page' => $url,
'country_code' => $geo_info['country_code'],
'city' => $geo_info['city'],
'device_type' => $device_info['device_type'],
'browser' => $device_info['browser'],
'os' => $device_info['os'],
'screen_resolution' => $this->get_screen_resolution(),
'is_new_visit' => 1,
'created_at' => current_time('mysql')
];
$this->db->insert($table_name, $data);
return $this->db->insert_id;
}
private function get_geo_info() {
// 简化版,实际应集成MaxMind GeoIP或类似服务
$ip = $this->get_client_ip();
// 本地IP返回空信息
if ($ip === '127.0.0.1' || strpos($ip, '192.168.') === 0) {
return ['country_code' => null, 'city' => null];
}
// 这里可以调用第三方API或本地数据库
// 示例:使用ipapi.co(免费版有限制)
return ['country_code' => null, 'city' => null];
}
private function parse_user_agent() {
$user_agent = $_SERVER['HTTP_USER_AGENT'] ?? '';
// 设备类型检测
$device_type = 'desktop';
if (preg_match('/(android|webos|iphone|ipad|ipod|blackberry|windows phone)/i', $user_agent)) {
$device_type = 'mobile';
} elseif (preg_match('/(tablet|ipad|playbook|silk)/i', $user_agent)) {
$device_type = 'tablet';
}
// 浏览器检测
$browser = 'Unknown';
if (preg_match('/MSIE|Trident/i', $user_agent)) {
$browser = 'Internet Explorer';
} elseif (preg_match('/Firefox/i', $user_agent)) {
$browser = 'Firefox';
} elseif (preg_match('/Chrome/i', $user_agent)) {
$browser = 'Chrome';
} elseif (preg_match('/Safari/i', $user_agent)) {
$browser = 'Safari';
} elseif (preg_match('/Edge/i', $user_agent)) {
$browser = 'Edge';
} elseif (preg_match('/Opera|OPR/i', $user_agent)) {
$browser = 'Opera';
}
// 操作系统检测
$os = 'Unknown';
if (preg_match('/Windows NT 10.0/i', $user_agent)) {
$os = 'Windows 10';
} elseif (preg_match('/Windows NT 6.3/i', $user_agent)) {
$os = 'Windows 8.1';
} elseif (preg_match('/Windows NT 6.2/i', $user_agent)) {
$os = 'Windows 8';
} elseif (preg_match('/Windows NT 6.1/i', $user_agent)) {
$os = 'Windows 7';
} elseif (preg_match('/Macintosh|Mac OS X/i', $user_agent)) {
$os = 'macOS';
} elseif (preg_match('/Linux/i', $user_agent)) {
$os = 'Linux';
} elseif (preg_match('/Android/i', $user_agent)) {
$os = 'Android';
} elseif (preg_match('/iPhone|iPad|iPod/i', $user_agent)) {
$os = 'iOS';
}
return [
'device_type' => $device_type,
'browser' => $browser,
'os' => $os
];
}
private function get_screen_resolution() {
// 通过JavaScript获取,这里先返回空值
return '';
}
private function set_frontend_data() {
add_action('wp_footer', function() {
?>
<script>
window.customStats = {
sessionId: '<?php echo esc_js($this->session_id); ?>',
visitId: <?php echo esc_js($this->current_visit_id); ?>,
nonce: '<?php echo wp_create_nonce('custom_stats_nonce'); ?>',
ajaxUrl: '<?php echo admin_url('admin-ajax.php'); ?>'
};
</script>
<?php
});
}
}
创建前端JavaScript文件,用于收集客户端数据:
// assets/js/frontend-tracker.js
(function() {
'use strict';
class FrontendTracker {
constructor() {
this.config = window.customStats || {};
this.pageStartTime = Date.now();
this.maxScrollDepth = 0;
this.init();
}
init() {
this.trackPageView();
this.trackScrollDepth();
this.trackTimeOnPage();
this.trackClicks();
this.trackFormSubmissions();
this.setupBeforeUnload();
}
trackPageView() {
const data = {
action: 'custom_stats_track_pageview',
nonce: this.config.nonce,
visit_id: this.config.visitId,
page_url: window.location.href,
page_title: document.title,
screen_resolution: this.getScreenResolution(),
viewport_size: this.getViewportSize()
};
this.sendRequest(data);
}
trackScrollDepth() {
let scrollCheckTimer;
const checkScrollDepth = () => {
const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
const scrollHeight = document.documentElement.scrollHeight - document.documentElement.clientHeight;
const scrollPercentage = scrollHeight > 0 ? Math.round((scrollTop / scrollHeight) * 100) : 0;
if (scrollPercentage > this.maxScrollDepth) {
this.maxScrollDepth = scrollPercentage;
// 记录25%、50%、75%、100%的关键点
if ([25, 50, 75, 100].includes(scrollPercentage)) {
const data = {
action: 'custom_stats_track_scroll',
nonce: this.config.nonce,
visit_id: this.config.visitId,
scroll_depth: scrollPercentage,
page_url: window.location.href
};
this.sendRequest(data);
}
}
};
window.addEventListener('scroll', () => {
clearTimeout(scrollCheckTimer);
scrollCheckTimer = setTimeout(checkScrollDepth, 100);
});
}
trackTimeOnPage() {
// 定期发送时间更新
setInterval(() => {
const timeOnPage = Math.round((Date.now() - this.pageStartTime) / 1000);
const data = {
action: 'custom_stats_update_time',
nonce: this.config.nonce,
visit_id: this.config.visitId,
time_on_page: timeOnPage
};
this.sendRequest(data);
}, 30000); // 每30秒发送一次
}
trackClicks() {
document.addEventListener('click', (e) => {
const target = e.target;
const link = target.closest('a');
if (link && link.href) {
const data = {
action: 'custom_stats_track_click',
nonce: this.config.nonce,
visit_id: this.config.visitId,
link_url: link.href,
link_text: link.textContent.substring(0, 100),
page_url: window.location.href
};
继续前端JavaScript代码:
// 如果是外部链接,立即发送数据
if (this.isExternalLink(link.href)) {
this.sendRequest(data, true); // 同步发送
} else {
this.sendRequest(data);
}
}
});
}
trackFormSubmissions() {
document.addEventListener('submit', (e) => {
const form = e.target;
const formId = form.id || form.name || 'unknown';
const data = {
action: 'custom_stats_track_form',
nonce: this.config.nonce,
visit_id: this.config.visitId,
form_id: formId,
form_action: form.action,
page_url: window.location.href
};
this.sendRequest(data);
});
}
setupBeforeUnload() {
window.addEventListener('beforeunload', () => {
const timeOnPage = Math.round((Date.now() - this.pageStartTime) / 1000);
const data = {
action: 'custom_stats_track_exit',
nonce: this.config.nonce,
visit_id: this.config.visitId,
time_on_page: timeOnPage,
scroll_depth: this.maxScrollDepth,
exit_page: window.location.href
};
// 使用navigator.sendBeacon进行可靠的离开页面数据发送
this.sendBeacon(data);
});
}
sendRequest(data, sync = false) {
const formData = new FormData();
for (const key in data) {
formData.append(key, data[key]);
}
if (sync) {
// 同步请求(用于离开页面时)
const xhr = new XMLHttpRequest();
xhr.open('POST', this.config.ajaxUrl, false);
xhr.send(formData);
} else {
// 异步请求
fetch(this.config.ajaxUrl, {
method: 'POST',
body: formData,
keepalive: true // 允许在页面卸载后继续发送
}).catch(error => {
console.error('Tracking error:', error);
});
}
}
sendBeacon(data) {
const blob = new Blob([JSON.stringify(data)], {type: 'application/json'});
navigator.sendBeacon(this.config.ajaxUrl + '?action=custom_stats_track_exit', blob);
}
getScreenResolution() {
return window.screen.width + 'x' + window.screen.height;
}
getViewportSize() {
return window.innerWidth + 'x' + window.innerHeight;
}
isExternalLink(url) {
const currentHost = window.location.hostname;
const linkHost = (new URL(url, window.location.href)).hostname;
return linkHost !== currentHost && linkHost !== '';
}
}
// 初始化追踪器
document.addEventListener('DOMContentLoaded', () => {
if (window.customStats) {
new FrontendTracker();
}
});
})();
创建AJAX请求处理类:
// includes/class-ajax-handler.php
class Custom_Stats_Ajax_Handler {
private $db;
public function __construct() {
global $wpdb;
$this->db = $wpdb;
$this->register_ajax_actions();
}
private function register_ajax_actions() {
// 页面浏览追踪
add_action('wp_ajax_custom_stats_track_pageview', [$this, 'handle_pageview']);
add_action('wp_ajax_nopriv_custom_stats_track_pageview', [$this, 'handle_pageview']);
// 滚动深度追踪
add_action('wp_ajax_custom_stats_track_scroll', [$this, 'handle_scroll']);
add_action('wp_ajax_nopriv_custom_stats_track_scroll', [$this, 'handle_scroll']);
// 点击追踪
add_action('wp_ajax_custom_stats_track_click', [$this, 'handle_click']);
add_action('wp_ajax_nopriv_custom_stats_track_click', [$this, 'handle_click']);
// 表单提交追踪
add_action('wp_ajax_custom_stats_track_form', [$this, 'handle_form']);
add_action('wp_ajax_nopriv_custom_stats_track_form', [$this, 'handle_form']);
// 退出页面追踪
add_action('wp_ajax_custom_stats_track_exit', [$this, 'handle_exit']);
add_action('wp_ajax_nopriv_custom_stats_track_exit', [$this, 'handle_exit']);
// 时间更新
add_action('wp_ajax_custom_stats_update_time', [$this, 'update_time']);
add_action('wp_ajax_nopriv_custom_stats_update_time', [$this, 'update_time']);
}
public function handle_pageview() {
$this->verify_nonce();
$visit_id = intval($_POST['visit_id']);
$page_url = sanitize_text_field($_POST['page_url']);
$page_title = sanitize_text_field($_POST['page_title']);
$screen_resolution = sanitize_text_field($_POST['screen_resolution']);
$table_name = $this->db->prefix . 'custom_page_views';
$data = [
'visit_id' => $visit_id,
'page_url' => $page_url,
'page_title' => $page_title,
'created_at' => current_time('mysql')
];
// 更新访问记录中的屏幕分辨率
if (!empty($screen_resolution)) {
$visits_table = $this->db->prefix . 'custom_visits';
$this->db->update(
$visits_table,
['screen_resolution' => $screen_resolution],
['id' => $visit_id]
);
}
$this->db->insert($table_name, $data);
wp_die('1');
}
public function handle_scroll() {
$this->verify_nonce();
$visit_id = intval($_POST['visit_id']);
$scroll_depth = intval($_POST['scroll_depth']);
$page_url = sanitize_text_field($_POST['page_url']);
$table_name = $this->db->prefix . 'custom_page_views';
// 找到当前页面的最新记录并更新滚动深度
$this->db->query(
$this->db->prepare(
"UPDATE $table_name
SET scroll_depth = %d
WHERE visit_id = %d
AND page_url = %s
ORDER BY created_at DESC
LIMIT 1",
$scroll_depth,
$visit_id,
$page_url
)
);
wp_die('1');
}
public function handle_click() {
$this->verify_nonce();
$visit_id = intval($_POST['visit_id']);
$link_url = esc_url_raw($_POST['link_url']);
$link_text = sanitize_text_field($_POST['link_text']);
$page_url = sanitize_text_field($_POST['page_url']);
$table_name = $this->db->prefix . 'custom_clicks';
// 创建点击记录表(如果不存在)
$this->create_clicks_table();
$data = [
'visit_id' => $visit_id,
'link_url' => $link_url,
'link_text' => $link_text,
'page_url' => $page_url,
'created_at' => current_time('mysql')
];
$this->db->insert($table_name, $data);
wp_die('1');
}
private function create_clicks_table() {
$table_name = $this->db->prefix . 'custom_clicks';
if ($this->db->get_var("SHOW TABLES LIKE '$table_name'") != $table_name) {
$charset_collate = $this->db->get_charset_collate();
$sql = "CREATE TABLE $table_name (
id bigint(20) NOT NULL AUTO_INCREMENT,
visit_id bigint(20) NOT NULL,
link_url varchar(512) NOT NULL,
link_text varchar(255) DEFAULT NULL,
page_url varchar(512) NOT NULL,
created_at datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id),
KEY visit_id (visit_id),
KEY link_url (link_url(191))
) $charset_collate;";
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
dbDelta($sql);
}
}
public function handle_form() {
$this->verify_nonce();
$visit_id = intval($_POST['visit_id']);
$form_id = sanitize_text_field($_POST['form_id']);
$form_action = esc_url_raw($_POST['form_action']);
$page_url = sanitize_text_field($_POST['page_url']);
$table_name = $this->db->prefix . 'custom_form_submissions';
// 创建表单提交表(如果不存在)
$this->create_forms_table();
$data = [
'visit_id' => $visit_id,
'form_id' => $form_id,
'form_action' => $form_action,
'page_url' => $page_url,
'created_at' => current_time('mysql')
];
$this->db->insert($table_name, $data);
wp_die('1');
}
private function create_forms_table() {
$table_name = $this->db->prefix . 'custom_form_submissions';
if ($this->db->get_var("SHOW TABLES LIKE '$table_name'") != $table_name) {
$charset_collate = $this->db->get_charset_collate();
$sql = "CREATE TABLE $table_name (
id bigint(20) NOT NULL AUTO_INCREMENT,
visit_id bigint(20) NOT NULL,
form_id varchar(100) NOT NULL,
form_action varchar(512) NOT NULL,
page_url varchar(512) NOT NULL,
created_at datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id),
KEY visit_id (visit_id),
KEY form_id (form_id)
) $charset_collate;";
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
dbDelta($sql);
}
}
public function handle_exit() {
// 对于sendBeacon请求,数据在php://input中
if ($_SERVER['REQUEST_METHOD'] === 'POST' && empty($_POST)) {
$input = file_get_contents('php://input');
$data = json_decode($input, true);
if ($data) {
$_POST = $data;
}
}
$visit_id = intval($_POST['visit_id']);
$time_on_page = intval($_POST['time_on_page']);
$scroll_depth = intval($_POST['scroll_depth']);
$exit_page = sanitize_text_field($_POST['exit_page']);
$table_name = $this->db->prefix . 'custom_visits';
$this->db->update(
$table_name,
[
'exit_page' => $exit_page,
'visit_duration' => $time_on_page,
'updated_at' => current_time('mysql')
],
['id' => $visit_id]
);
// 更新最后页面的滚动深度
$page_views_table = $this->db->prefix . 'custom_page_views';
$this->db->query(
$this->db->prepare(
"UPDATE $page_views_table
SET scroll_depth = %d
WHERE visit_id = %d
ORDER BY created_at DESC
LIMIT 1",
$scroll_depth,
$visit_id
)
);
wp_die('1');
}
public function update_time() {
$this->verify_nonce();
$visit_id = intval($_POST['visit_id']);
$time_on_page = intval($_POST['time_on_page']);
$table_name = $this->db->prefix . 'custom_visits';
$this->db->update(
$table_name,
[
'visit_duration' => $time_on_page,
'updated_at' => current_time('mysql')
],
['id' => $visit_id]
);
wp_die('1');
}
private function verify_nonce() {
if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'custom_stats_nonce')) {
wp_die('Security check failed', 403);
}
}
}
创建数据统计和报表生成类:
// includes/class-statistics.php
class Custom_Stats_Statistics {
private $db;
public function __construct() {
global $wpdb;
$this->db = $wpdb;
}
public function get_daily_stats($date = null) {
if (!$date) {
$date = current_time('Y-m-d');
}
$visits_table = $this->db->prefix . 'custom_visits';
$page_views_table = $this->db->prefix . 'custom_page_views';
$stats = [
'date' => $date,
'visits' => 0,
'unique_visitors' => 0,
'pageviews' => 0,
'avg_duration' => 0,
'bounce_rate' => 0
];
// 获取总访问数
$stats['visits'] = $this->db->get_var(
$this->db->prepare(
"SELECT COUNT(*) FROM $visits_table WHERE DATE(created_at) = %s",
$date
)
);
// 获取独立访客数
$stats['unique_visitors'] = $this->db->get_var(
$this->db->prepare(
"SELECT COUNT(DISTINCT session_id) FROM $visits_table WHERE DATE(created_at) = %s",
$date
)
);
// 获取总页面浏览量
$stats['pageviews'] = $this->db->get_var(
$this->db->prepare(
"SELECT COUNT(*) FROM $page_views_table pv
INNER JOIN $visits_table v ON pv.visit_id = v.id
WHERE DATE(v.created_at) = %s",
$date
)
);
// 获取平均访问时长
$avg_duration = $this->db->get_var(
$this->db->prepare(
"SELECT AVG(visit_duration) FROM $visits_table
WHERE DATE(created_at) = %s AND visit_duration > 0",
$date
)
);
$stats['avg_duration'] = $avg_duration ? round($avg_duration) : 0;
// 计算跳出率(只浏览一个页面且停留时间短于30秒)
$bounce_count = $this->db->get_var(
$this->db->prepare(
"SELECT COUNT(*) FROM (
SELECT v.id, COUNT(pv.id) as page_count, v.visit_duration
FROM $visits_table v
LEFT JOIN $page_views_table pv ON v.id = pv.visit_id
WHERE DATE(v.created_at) = %s
GROUP BY v.id
HAVING page_count = 1 AND visit_duration < 30
) as bounces",
$date
)
);
if ($stats['visits'] > 0) {
$stats['bounce_rate'] = round(($bounce_count / $stats['visits']) * 100, 2);
}
return $stats;
}
public function get_top_pages($limit = 10, $period = 'today') {
$page_views_table = $this->db->prefix . 'custom_page_views';
$visits_table = $this->db->prefix . 'custom_visits';
$where_clause = $this->get_period_where_clause($period, 'v.created_at');
$query = $this->db->prepare(
"SELECT pv.page_url, pv.page_title,
COUNT(pv.id) as views,
COUNT(DISTINCT v.session_id) as unique_visitors,
AVG(pv.scroll_depth) as avg_scroll_depth,
AVG(v.visit_duration) as avg_time_on_page
FROM $page_views_table pv
INNER JOIN $visits_table v ON pv.visit_id = v.id
WHERE 1=1 $where_clause
GROUP BY pv.page_url
ORDER BY views DESC
LIMIT %d",
$limit
);
return $this->db->get_results($query);
}
public function get_traffic_sources($period = 'today') {
$visits_table = $this->db->prefix . 'custom_visits';
$where_clause = $this->get_period_where_clause($period);
$query = "SELECT
CASE
WHEN referrer = '' THEN '直接访问'
WHEN referrer LIKE '%' || %s || '%' THEN '内部链接'
WHEN referrer LIKE '%google.%' THEN 'Google'
WHEN referrer LIKE '%bing.%' THEN 'Bing'
WHEN referrer LIKE '%baidu.%' THEN '百度'
WHEN referrer LIKE '%yahoo.%' THEN 'Yahoo'
WHEN referrer LIKE '%facebook.%' THEN 'Facebook'
WHEN referrer LIKE '%twitter.%' THEN 'Twitter'
WHEN referrer LIKE '%linkedin.%' THEN 'LinkedIn'
ELSE '其他推荐'
END as source,
COUNT(*) as visits,
COUNT(DISTINCT session_id) as unique_visitors,
AVG(visit_duration) as avg_duration
FROM $visits_table


