文章目录[隐藏]
网络传媒WordPress站点柔性广告效果归因分析插件教程
引言:广告效果归因的重要性
在数字营销时代,网络传媒站点面临着广告效果追踪与分析的挑战。广告投放渠道多样化,用户转化路径复杂,如何准确归因每个广告渠道对最终转化的贡献,成为优化广告预算分配的关键。本教程将详细介绍如何为WordPress站点开发一个柔性广告效果归因分析插件,帮助您精确追踪多触点转化路径。
插件功能概述
本插件将实现以下核心功能:
- 多触点广告转化路径追踪
- 灵活归因模型配置(首次点击、末次点击、线性归因等)
- 广告渠道效果可视化报表
- 与Google Analytics等第三方工具的数据对接
- 自定义转化事件定义与追踪
环境准备与插件基础结构
1. 创建插件基础文件
<?php
/**
* Plugin Name: 柔性广告效果归因分析
* Plugin URI: https://yourwebsite.com/
* Description: 用于WordPress站点的多触点广告效果归因分析工具
* Version: 1.0.0
* Author: 您的名称
* License: GPL v2 or later
*/
// 防止直接访问
if (!defined('ABSPATH')) {
exit;
}
// 定义插件常量
define('AA_PLUGIN_PATH', plugin_dir_path(__FILE__));
define('AA_PLUGIN_URL', plugin_dir_url(__FILE__));
define('AA_VERSION', '1.0.0');
// 初始化插件
require_once AA_PLUGIN_PATH . 'includes/class-attribution-core.php';
function aa_init_plugin() {
$plugin = new Attribution_Analysis_Core();
$plugin->run();
}
add_action('plugins_loaded', 'aa_init_plugin');
?>
2. 创建核心类文件
<?php
// includes/class-attribution-core.php
class Attribution_Analysis_Core {
public function __construct() {
// 构造函数
}
public function run() {
$this->setup_hooks();
$this->init_modules();
}
private function setup_hooks() {
// 注册激活/停用钩子
register_activation_hook(__FILE__, array($this, 'activate_plugin'));
register_deactivation_hook(__FILE__, array($this, 'deactivate_plugin'));
// 添加管理菜单
add_action('admin_menu', array($this, 'add_admin_menu'));
// 前端追踪脚本
add_action('wp_footer', array($this, 'add_tracking_script'));
// 处理转化事件
add_action('wp_ajax_aa_track_conversion', array($this, 'track_conversion'));
add_action('wp_ajax_nopriv_aa_track_conversion', array($this, 'track_conversion'));
}
private function init_modules() {
// 初始化数据库模块
require_once AA_PLUGIN_PATH . 'includes/class-database-manager.php';
$this->db_manager = new Attribution_Database_Manager();
// 初始化归因模型模块
require_once AA_PLUGIN_PATH . 'includes/class-attribution-models.php';
$this->attribution_models = new Attribution_Models();
// 初始化报表模块
require_once AA_PLUGIN_PATH . 'includes/class-reports-generator.php';
$this->reports = new Reports_Generator();
}
public function activate_plugin() {
// 创建数据库表
$this->db_manager->create_tables();
// 设置默认选项
$default_options = array(
'attribution_model' => 'last_click',
'conversion_window' => 30,
'tracking_enabled' => true
);
update_option('aa_plugin_settings', $default_options);
}
public function deactivate_plugin() {
// 清理临时数据
// 注意:不删除历史数据,以便重新激活时保留
}
public function add_admin_menu() {
add_menu_page(
'广告归因分析',
'广告归因',
'manage_options',
'attribution-analysis',
array($this, 'render_admin_dashboard'),
'dashicons-chart-line',
30
);
// 添加子菜单
add_submenu_page(
'attribution-analysis',
'归因设置',
'设置',
'manage_options',
'aa-settings',
array($this, 'render_settings_page')
);
add_submenu_page(
'attribution-analysis',
'转化报表',
'报表',
'manage_options',
'aa-reports',
array($this, 'render_reports_page')
);
}
public function add_tracking_script() {
// 前端追踪脚本将在后续部分实现
}
public function track_conversion() {
// AJAX处理转化事件
}
public function render_admin_dashboard() {
// 渲染管理仪表板
include AA_PLUGIN_PATH . 'admin/views/dashboard.php';
}
public function render_settings_page() {
// 渲染设置页面
include AA_PLUGIN_PATH . 'admin/views/settings.php';
}
public function render_reports_page() {
// 渲染报表页面
include AA_PLUGIN_PATH . 'admin/views/reports.php';
}
}
?>
数据库设计与实现
3. 数据库管理类
<?php
// includes/class-database-manager.php
class Attribution_Database_Manager {
private $charset_collate;
public function __construct() {
global $wpdb;
$this->charset_collate = $wpdb->get_charset_collate();
}
public function create_tables() {
global $wpdb;
$table_name_sessions = $wpdb->prefix . 'aa_ad_sessions';
$table_name_conversions = $wpdb->prefix . 'aa_conversions';
$table_name_touchpoints = $wpdb->prefix . 'aa_touchpoints';
// 广告会话表
$sql_sessions = "CREATE TABLE IF NOT EXISTS $table_name_sessions (
session_id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
visitor_id VARCHAR(32) NOT NULL,
landing_page VARCHAR(500) NOT NULL,
referrer VARCHAR(500),
utm_source VARCHAR(100),
utm_medium VARCHAR(100),
utm_campaign VARCHAR(100),
utm_term VARCHAR(100),
utm_content VARCHAR(100),
device_type VARCHAR(50),
browser VARCHAR(100),
ip_address VARCHAR(45),
session_start DATETIME NOT NULL,
session_end DATETIME,
PRIMARY KEY (session_id),
INDEX visitor_idx (visitor_id),
INDEX session_start_idx (session_start)
) $this->charset_collate;";
// 转化事件表
$sql_conversions = "CREATE TABLE IF NOT EXISTS $table_name_conversions (
conversion_id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
visitor_id VARCHAR(32) NOT NULL,
conversion_type VARCHAR(50) NOT NULL,
conversion_value DECIMAL(10,2),
conversion_data TEXT,
conversion_time DATETIME NOT NULL,
attributed_session_id BIGINT(20) UNSIGNED,
attribution_model VARCHAR(50),
PRIMARY KEY (conversion_id),
INDEX visitor_idx (visitor_id),
INDEX conversion_time_idx (conversion_time),
FOREIGN KEY (attributed_session_id) REFERENCES $table_name_sessions(session_id) ON DELETE SET NULL
) $this->charset_collate;";
// 触点路径表
$sql_touchpoints = "CREATE TABLE IF NOT EXISTS $table_name_touchpoints (
touchpoint_id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
visitor_id VARCHAR(32) NOT NULL,
session_id BIGINT(20) UNSIGNED NOT NULL,
touchpoint_order INT NOT NULL,
touchpoint_time DATETIME NOT NULL,
channel_group VARCHAR(100),
channel_detail VARCHAR(200),
interaction_type VARCHAR(50),
cost DECIMAL(10,2) DEFAULT 0.00,
PRIMARY KEY (touchpoint_id),
INDEX visitor_session_idx (visitor_id, session_id),
FOREIGN KEY (session_id) REFERENCES $table_name_sessions(session_id) ON DELETE CASCADE
) $this->charset_collate;";
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
dbDelta($sql_sessions);
dbDelta($sql_conversions);
dbDelta($sql_touchpoints);
}
public function save_session($session_data) {
global $wpdb;
$table_name = $wpdb->prefix . 'aa_ad_sessions';
$wpdb->insert(
$table_name,
$session_data
);
return $wpdb->insert_id;
}
public function save_touchpoint($touchpoint_data) {
global $wpdb;
$table_name = $wpdb->prefix . 'aa_touchpoints';
$wpdb->insert(
$table_name,
$touchpoint_data
);
return $wpdb->insert_id;
}
public function save_conversion($conversion_data) {
global $wpdb;
$table_name = $wpdb->prefix . 'aa_conversions';
$wpdb->insert(
$table_name,
$conversion_data
);
return $wpdb->insert_id;
}
public function get_conversion_path($visitor_id, $days_back = 30) {
global $wpdb;
$table_touchpoints = $wpdb->prefix . 'aa_touchpoints';
$table_sessions = $wpdb->prefix . 'aa_ad_sessions';
$query = $wpdb->prepare(
"SELECT
tp.touchpoint_id,
tp.touchpoint_order,
tp.touchpoint_time,
tp.channel_group,
tp.channel_detail,
tp.interaction_type,
s.utm_source,
s.utm_medium,
s.utm_campaign
FROM $table_touchpoints tp
JOIN $table_sessions s ON tp.session_id = s.session_id
WHERE tp.visitor_id = %s
AND tp.touchpoint_time >= DATE_SUB(NOW(), INTERVAL %d DAY)
ORDER BY tp.touchpoint_time ASC",
$visitor_id,
$days_back
);
return $wpdb->get_results($query);
}
}
?>
前端追踪脚本实现
4. JavaScript追踪代码
// assets/js/tracking.js
(function() {
'use strict';
// 生成唯一访客ID(如果不存在)
function getVisitorId() {
let visitorId = localStorage.getItem('aa_visitor_id');
if (!visitorId) {
visitorId = 'vis_' + Math.random().toString(36).substr(2, 9) +
'_' + Date.now().toString(36);
localStorage.setItem('aa_visitor_id', visitorId);
}
return visitorId;
}
// 获取UTM参数
function getUTMParams() {
const params = new URLSearchParams(window.location.search);
return {
source: params.get('utm_source') || '',
medium: params.get('utm_medium') || '',
campaign: params.get('utm_campaign') || '',
term: params.get('utm_term') || '',
content: params.get('utm_content') || ''
};
}
// 获取设备信息
function getDeviceInfo() {
const ua = navigator.userAgent;
let deviceType = 'desktop';
if (/Mobile|Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(ua)) {
deviceType = 'mobile';
} else if (/Tablet|iPad/i.test(ua)) {
deviceType = 'tablet';
}
return {
deviceType: deviceType,
browser: navigator.userAgent,
screenResolution: screen.width + 'x' + screen.height
};
}
// 发送追踪数据到服务器
function sendTrackingData(data, endpoint) {
const xhr = new XMLHttpRequest();
xhr.open('POST', aa_tracking.ajax_url, true);
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.onreadystatechange = function() {
if (xhr.readyState === 4 && xhr.status === 200) {
console.log('Tracking data sent successfully');
}
};
const params = new URLSearchParams();
params.append('action', endpoint);
params.append('data', JSON.stringify(data));
params.append('nonce', aa_tracking.nonce);
xhr.send(params.toString());
}
// 追踪页面访问
function trackPageView() {
const visitorId = getVisitorId();
const utmParams = getUTMParams();
const deviceInfo = getDeviceInfo();
const trackingData = {
visitor_id: visitorId,
page_url: window.location.href,
referrer: document.referrer,
utm_source: utmParams.source,
utm_medium: utmParams.medium,
utm_campaign: utmParams.campaign,
utm_term: utmParams.term,
utm_content: utmParams.content,
device_type: deviceInfo.deviceType,
browser: deviceInfo.browser,
screen_resolution: deviceInfo.screenResolution,
timestamp: new Date().toISOString()
};
sendTrackingData(trackingData, 'aa_track_session');
}
// 追踪转化事件
function trackConversion(conversionType, conversionValue = 0, customData = {}) {
const visitorId = getVisitorId();
const conversionData = {
visitor_id: visitorId,
conversion_type: conversionType,
conversion_value: conversionValue,
custom_data: customData,
page_url: window.location.href,
timestamp: new Date().toISOString()
};
sendTrackingData(conversionData, 'aa_track_conversion');
// 触发数据层事件(用于Google Tag Manager等)
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
'event': 'aa_conversion',
'conversion_type': conversionType,
'conversion_value': conversionValue
});
}
// 初始化追踪
document.addEventListener('DOMContentLoaded', function() {
// 追踪页面访问
trackPageView();
// 为转化按钮添加事件监听(示例)
const conversionButtons = document.querySelectorAll('[data-aa-conversion]');
conversionButtons.forEach(button => {
button.addEventListener('click', function() {
const conversionType = this.getAttribute('data-aa-conversion');
const conversionValue = this.getAttribute('data-aa-value') || 0;
trackConversion(conversionType, conversionValue, {
button_text: this.textContent,
button_id: this.id
});
});
});
// 表单提交追踪
const trackedForms = document.querySelectorAll('form[data-aa-conversion]');
trackedForms.forEach(form => {
form.addEventListener('submit', function(e) {
const conversionType = this.getAttribute('data-aa-conversion');
const conversionValue = this.getAttribute('data-aa-value') || 0;
// 可以添加表单验证逻辑
trackConversion(conversionType, conversionValue, {
form_id: this.id,
form_action: this.action
});
});
});
});
// 暴露公共API
window.AttributionAnalytics = {
trackConversion: trackConversion,
getVisitorId: getVisitorId
};
})();
归因模型实现
5. 归因模型计算类
<?php
// includes/class-attribution-models.php
class Attribution_Models {
public function __construct() {
// 初始化归因模型
}
/**
* 应用归因模型分配转化价值
*
* @param array $touchpoints 触点路径数组
* @param float $conversion_value 转化价值
* @param string $model_type 归因模型类型
* @return array 分配后的触点价值数组
*/
public function apply_attribution_model($touchpoints, $conversion_value, $model_type = 'last_click') {
if (empty($touchpoints)) {
return array();
}
$touchpoint_count = count($touchpoints);
$attributed_values = array();
switch ($model_type) {
case 'last_click':
// 末次点击归因:100%价值给最后触点
foreach ($touchpoints as $index => $touchpoint) {
$attributed_values[$index] = ($index === $touchpoint_count - 1) ?
$conversion_value : 0;
}
break;
case 'first_click':
// 首次点击归因:100%价值给首次触点
foreach ($touchpoints as $index => $touchpoint) {
$attributed_values[$index] = ($index === 0) ?
$conversion_value : 0;
}
break;
case 'linear':
// 线性归因:价值平均分配
$value_per_touchpoint = $conversion_value / $touchpoint_count;
foreach ($touchpoints as $index => $touchpoint) {
$attributed_values[$index] = $value_per_touchpoint;
}
break;
case 'time_decay':
// 时间衰减归因:越接近转化的触点获得越多价值
$total_weight = 0;
$weights = array();
// 计算每个触点的时间权重(指数衰减)
foreach ($touchpoints as $index => $touchpoint) {
$time_index = $index + 1; // 避免0次方
time_index); // 指数衰减因子
$weights[$index] = $weight;
$total_weight += $weight;
}
// 根据权重分配价值
foreach ($touchpoints as $index => $touchpoint) {
$attributed_values[$index] = ($weights[$index] / $total_weight) * $conversion_value;
}
break;
case 'position_based':
// 位置归因:首尾各40%,中间触点平分20%
$first_last_percentage = 0.4; // 40%
$middle_percentage = 0.2; // 20%
if ($touchpoint_count === 1) {
// 只有一个触点时获得100%
$attributed_values[0] = $conversion_value;
} elseif ($touchpoint_count === 2) {
// 两个触点时各50%
$attributed_values[0] = $conversion_value * 0.5;
$attributed_values[1] = $conversion_value * 0.5;
} else {
// 三个及以上触点
$first_last_value = $conversion_value * $first_last_percentage;
$middle_value_total = $conversion_value * $middle_percentage;
$middle_touchpoints = $touchpoint_count - 2;
$middle_value_each = $middle_value_total / $middle_touchpoints;
foreach ($touchpoints as $index => $touchpoint) {
if ($index === 0 || $index === $touchpoint_count - 1) {
$attributed_values[$index] = $first_last_value;
} else {
$attributed_values[$index] = $middle_value_each;
}
}
}
break;
case 'custom_algorithm':
// 自定义算法归因(基于机器学习或业务规则)
$attributed_values = $this->custom_attribution_algorithm($touchpoints, $conversion_value);
break;
default:
// 默认使用末次点击
foreach ($touchpoints as $index => $touchpoint) {
$attributed_values[$index] = ($index === $touchpoint_count - 1) ?
$conversion_value : 0;
}
}
return $attributed_values;
}
/**
* 自定义归因算法示例
*/
private function custom_attribution_algorithm($touchpoints, $conversion_value) {
$attributed_values = array();
$touchpoint_count = count($touchpoints);
// 示例:基于渠道类型和互动时间的加权算法
$total_weight = 0;
$weights = array();
foreach ($touchpoints as $index => $touchpoint) {
$base_weight = 1.0;
// 根据渠道类型调整权重
$channel_weight = $this->get_channel_weight($touchpoint['channel_group']);
// 根据时间位置调整权重(越接近转化权重越高)
$time_weight = ($index + 1) / $touchpoint_count;
// 根据互动类型调整权重
$interaction_weight = $this->get_interaction_weight($touchpoint['interaction_type']);
// 计算综合权重
$weight = $base_weight * $channel_weight * $time_weight * $interaction_weight;
$weights[$index] = $weight;
$total_weight += $weight;
}
// 根据权重分配价值
foreach ($touchpoints as $index => $touchpoint) {
if ($total_weight > 0) {
$attributed_values[$index] = ($weights[$index] / $total_weight) * $conversion_value;
} else {
$attributed_values[$index] = 0;
}
}
return $attributed_values;
}
/**
* 获取渠道权重
*/
private function get_channel_weight($channel_group) {
$channel_weights = array(
'paid_search' => 1.2,
'display_ads' => 1.0,
'social_media' => 1.1,
'email' => 1.3,
'organic_search' => 0.9,
'direct' => 0.8,
'referral' => 1.0
);
return isset($channel_weights[$channel_group]) ?
$channel_weights[$channel_group] : 1.0;
}
/**
* 获取互动类型权重
*/
private function get_interaction_weight($interaction_type) {
$interaction_weights = array(
'click' => 1.0,
'view' => 0.3,
'engagement' => 0.7,
'form_submit' => 1.5
);
return isset($interaction_weights[$interaction_type]) ?
$interaction_weights[$interaction_type] : 1.0;
}
/**
* 批量处理转化归因
*/
public function batch_process_conversions($conversion_ids, $model_type = null) {
global $wpdb;
if (empty($model_type)) {
$settings = get_option('aa_plugin_settings', array());
$model_type = isset($settings['attribution_model']) ?
$settings['attribution_model'] : 'last_click';
}
$table_conversions = $wpdb->prefix . 'aa_conversions';
$table_touchpoints = $wpdb->prefix . 'aa_touchpoints';
foreach ($conversion_ids as $conversion_id) {
// 获取转化信息
$conversion = $wpdb->get_row($wpdb->prepare(
"SELECT * FROM $table_conversions WHERE conversion_id = %d",
$conversion_id
));
if (!$conversion) continue;
// 获取该访客的触点路径
$touchpoints = $wpdb->get_results($wpdb->prepare(
"SELECT * FROM $table_touchpoints
WHERE visitor_id = %s
AND touchpoint_time <= %s
ORDER BY touchpoint_time ASC",
$conversion->visitor_id,
$conversion->conversion_time
));
if (empty($touchpoints)) continue;
// 应用归因模型
$attributed_values = $this->apply_attribution_model(
$touchpoints,
floatval($conversion->conversion_value),
$model_type
);
// 更新触点表的归因价值
foreach ($touchpoints as $index => $touchpoint) {
$wpdb->update(
$table_touchpoints,
array(
'attributed_value' => $attributed_values[$index],
'attribution_model' => $model_type,
'attribution_time' => current_time('mysql')
),
array('touchpoint_id' => $touchpoint->touchpoint_id)
);
}
// 更新转化表的归因信息
$wpdb->update(
$table_conversions,
array(
'attribution_model' => $model_type,
'attribution_processed' => 1
),
array('conversion_id' => $conversion_id)
);
}
return count($conversion_ids);
}
}
?>
## 数据可视化与报表系统
### 6. 报表生成类
<?php
// includes/class-reports-generator.php
class Reports_Generator {
public function __construct() {
// 初始化报表系统
}
/**
* 生成渠道效果报表
*/
public function generate_channel_report($start_date, $end_date, $model_type = null) {
global $wpdb;
if (empty($model_type)) {
$settings = get_option('aa_plugin_settings', array());
$model_type = isset($settings['attribution_model']) ?
$settings['attribution_model'] : 'last_click';
}
$table_touchpoints = $wpdb->prefix . 'aa_touchpoints';
$table_conversions = $wpdb->prefix . 'aa_conversions';
$query = $wpdb->prepare(
"SELECT
tp.channel_group,
tp.channel_detail,
COUNT(DISTINCT tp.visitor_id) as unique_visitors,
COUNT(tp.touchpoint_id) as total_touchpoints,
COUNT(DISTINCT c.conversion_id) as conversions,
SUM(c.conversion_value) as total_conversion_value,
SUM(tp.attributed_value) as attributed_value,
AVG(tp.cost) as avg_cost
FROM $table_touchpoints tp
LEFT JOIN $table_conversions c ON tp.visitor_id = c.visitor_id
AND c.conversion_time BETWEEN %s AND %s
AND c.attribution_model = %s
WHERE tp.touchpoint_time BETWEEN %s AND %s
AND tp.attribution_model = %s
GROUP BY tp.channel_group, tp.channel_detail
ORDER BY attributed_value DESC",
$start_date, $end_date, $model_type,
$start_date, $end_date, $model_type
);
$results = $wpdb->get_results($query);
// 计算ROI和其他指标
foreach ($results as &$row) {
if ($row->avg_cost > 0) {
$row->roi = ($row->attributed_value - $row->avg_cost) / $row->avg_cost * 100;
} else {
$row->roi = null;
}
if ($row->total_touchpoints > 0) {
$row->conversion_rate = ($row->conversions / $row->total_touchpoints) * 100;
} else {
$row->conversion_rate = 0;
}
}
return $results;
}
/**
* 生成转化路径分析报表
*/
public function generate_path_analysis($limit = 20) {
global $wpdb;
$table_touchpoints = $wpdb->prefix . 'aa_touchpoints';
$table_conversions = $wpdb->prefix . 'aa_conversions';
$query = $wpdb->prepare(
"SELECT
c.visitor_id,
GROUP_CONCAT(tp.channel_group ORDER BY tp.touchpoint_time ASC SEPARATOR ' > ') as path,
COUNT(tp.touchpoint_id) as path_length,
c.conversion_type,
c.conversion_value,
c.conversion_time
FROM $table_conversions c
JOIN $table_touchpoints tp ON c.visitor_id = tp.visitor_id
AND tp.touchpoint_time <= c.conversion_time
WHERE c.attribution_processed = 1
GROUP BY c.conversion_id
HAVING path_length > 1
ORDER BY c.conversion_value DESC
LIMIT %d",
$limit
);
return $wpdb->get_results($query);
}
/**
* 生成时间趋势报表
*/
public function generate_trend_report($period = 'daily', $days = 30) {
global $wpdb;
$table_conversions = $wpdb->prefix . 'aa_conversions';
$table_touchpoints = $wpdb->prefix . 'aa_touchpoints';
$date_format = '';
switch ($period) {
case 'hourly':
$date_format = '%Y-%m-%d %H:00:00';
break;
case 'daily':
$date_format = '%Y-%m-%d';
break;
case 'weekly':
$date_format = '%Y-%U';
break;
case 'monthly':
$date_format = '%Y-%m';
break;
default:
$date_format = '%Y-%m-%d';
}
$query = $wpdb->prepare(
"SELECT
DATE_FORMAT(c.conversion_time, %s) as period,
COUNT(DISTINCT c.conversion_id) as conversions,
SUM(c.conversion_value) as total_value,
COUNT(DISTINCT tp.visitor_id) as engaged_visitors,
COUNT(tp.touchpoint_id) as touchpoints
FROM $table_conversions c
LEFT JOIN $table_touchpoints tp ON DATE(tp.touchpoint_time) = DATE(c.conversion_time)
WHERE c.conversion_time >= DATE_SUB(NOW(), INTERVAL %d DAY)
GROUP BY period
ORDER BY period ASC",
$date_format,
$days
);
return $wpdb->get_results($query);
}
/**
* 生成归因模型对比报表
*/
public function generate_model_comparison($start_date, $end_date) {
global $wpdb;
$table_conversions = $wpdb->prefix . 'aa_conversions';
$models = array('last_click', 'first_click', 'linear', 'time_decay', 'position_based');
$results = array();
foreach ($models as $model) {
$query = $wpdb->prepare(
"SELECT
%s as model_name,
COUNT(DISTINCT conversion_id) as conversions,
SUM(conversion_value) as total_value,
AVG(conversion_value) as avg_value
FROM $table_conversions
WHERE conversion_time BETWEEN %s AND %s
AND attribution_model = %s",
$model, $start_date, $end_date, $model
);
$result = $wpdb->get_row($query);
if ($result) {
$results[] = $result;
}
}
return $results;
}
/**
* 生成数据导出(CSV格式)
*/
public function export_report_data($report_type, $params) {
$data = array();
switch ($report_type) {
case 'channel_performance':
$data = $this->generate_channel_report(
$params['start_date'],
$params['end_date'],
$params['model_type']
);
$filename = 'channel-performance-' . date('Y-m-d') . '.csv';
$headers = array('渠道组', '渠道详情', '独立访客', '总触点', '转化数',
'转化总值', '归因价值', '平均成本', 'ROI', '转化率');
break;
case 'path_analysis':
$data = $this->generate_path_analysis($params['limit']);
$filename = 'path-analysis-' . date('Y-m-d') . '.csv';
$headers = array('访客ID', '转化路径', '路径长度', '转化类型',
'转化价值', '转化时间');
break;
case 'trend':
$data = $this->generate_trend_report($params['period'], $params['days']);
$filename = 'trend-report-' . date('Y-m-d') . '.csv';
$headers = array('时间段', '转化数', '总价值', '参与访客', '触点数量');
break;
default:
return false;
}
// 生成CSV内容
$output = fopen('php://output', 'w');
// 添加BOM头,确保Excel正确识别UTF-8
fwrite($output, "xEFxBBxBF");
// 写入表头
fputcsv($output, $headers);
// 写入数据
foreach ($data as $row) {
fputcsv($output, (array)$row);
}
fclose($output);
// 设置HTTP头
header('Content-Type: text/csv; charset=utf-8');
header('Content-Disposition: attachment; filename="' . $filename . '"');
return true;
}
}
?>
## 管理界面实现
### 7. 管理仪表板视图
<!-- admin/views/dashboard.php -->
<div class="wrap">
<h1><?php echo esc_html(get_admin_page_title()); ?></h1>
<div class="aa-dashboard-container">
<!-- 概览卡片 -->
<div class="aa-overview-cards">
<div class="aa-card">
<h3>今日转化</h3>
<div class="aa-card-value" id="today-conversions">0</div>
<div class="aa-card-change" id="today-change">+0%</div>
</div>
<div class="aa-card">
<h3>本月收入</h3>
<div class="aa-card-value" id="monthly-revenue">¥0</div>
<div class="aa-card-change" id="monthly-change">+0%</div>
</div>
<div class="aa-card">
<h3>平均转化价值</h3>
<div class="aa-card-value" id="avg-conversion-value">¥0</div>
<div class="aa-card-change" id="avg-change">+0%</div>
</div>
<div class="aa-card">
<h3>归因完成率</h3>
<div class="aa-card-value" id="attribution-rate">0%</div>
<div class="aa-card-progress">
<div class="aa-progress-bar" id="attribution-progress"></div>
</div>
</div>
</div>
<!-- 图表区域 -->
<div class="aa-charts-section">
<div class="aa-chart-container">
<h3>渠道效果对比</h3>
<canvas id="channel-performance-chart" width="400" height="200"></canvas>
</div>
<div class="aa-chart-container">
<h3>转化趋势</h3>
<canvas id="conversion-trend-chart" width="400" height="200"></canvas>
</div>
</div>
<!-- 数据表格 -->
<div class="aa-data-table">
<h3>最近转化</h3>
<table class="wp-list-table widefat fixed striped">
<thead>
<tr>
<th>时间</th>
<th>访客ID</th>
<th>转化类型</


