文章目录[隐藏]
WordPress网络传媒柔性广告库存动态分配插件开发教程
一、插件开发背景与需求分析
在当今数字广告领域,网络传媒平台面临着广告库存分配不均、填充率低、收益最大化的挑战。传统的固定广告位分配方式已无法满足动态市场需求,因此开发一款能够智能分配广告库存的WordPress插件变得尤为重要。
柔性广告库存动态分配插件能够根据以下因素自动调整广告展示策略:
- 流量来源和用户特征
- 广告主预算和竞价情况
- 时段和季节性因素
- 内容相关性和用户兴趣
本教程将指导您从零开始开发一个功能完整的WordPress广告库存动态分配插件。
二、插件基础架构搭建
首先,我们需要创建插件的基本文件结构:
<?php
/**
* Plugin Name: 柔性广告库存动态分配系统
* Plugin URI: https://yourwebsite.com/
* Description: 智能动态分配广告库存,最大化广告收益
* Version: 1.0.0
* Author: 你的名字
* License: GPL v2 or later
*/
// 防止直接访问
if (!defined('ABSPATH')) {
exit;
}
// 定义插件常量
define('FAA_VERSION', '1.0.0');
define('FAA_PLUGIN_DIR', plugin_dir_path(__FILE__));
define('FAA_PLUGIN_URL', plugin_dir_url(__FILE__));
// 初始化插件
class FlexibleAdAllocation {
private static $instance = null;
public static function get_instance() {
if (null === self::$instance) {
self::$instance = new self();
}
return self::$instance;
}
private function __construct() {
$this->init_hooks();
}
private function init_hooks() {
// 激活/停用钩子
register_activation_hook(__FILE__, array($this, 'activate'));
register_deactivation_hook(__FILE__, array($this, 'deactivate'));
// 管理菜单
add_action('admin_menu', array($this, 'add_admin_menu'));
// 前端广告展示
add_action('wp_footer', array($this, 'display_dynamic_ad'));
// 短码支持
add_shortcode('flexible_ad', array($this, 'ad_shortcode'));
}
public function activate() {
// 创建数据库表
$this->create_database_tables();
// 设置默认选项
$this->set_default_options();
}
public function deactivate() {
// 清理临时数据
// 注意:不删除历史数据以便重新激活时使用
}
// 其他方法将在后续部分实现
}
// 启动插件
FlexibleAdAllocation::get_instance();
?>
三、数据库设计与实现
广告库存管理需要高效的数据存储结构,以下是数据库表的创建代码:
<?php
/**
* 创建插件所需的数据库表
*/
private function create_database_tables() {
global $wpdb;
$charset_collate = $wpdb->get_charset_collate();
$table_name_ad_inventory = $wpdb->prefix . 'faa_ad_inventory';
$table_name_ad_performance = $wpdb->prefix . 'faa_ad_performance';
// 广告库存表
$sql_ad_inventory = "CREATE TABLE IF NOT EXISTS $table_name_ad_inventory (
id mediumint(9) NOT NULL AUTO_INCREMENT,
ad_name varchar(255) NOT NULL,
ad_code text NOT NULL,
ad_type varchar(50) DEFAULT 'banner',
priority int(11) DEFAULT 5,
daily_cap int(11) DEFAULT 0,
total_impressions int(11) DEFAULT 0,
total_clicks int(11) DEFAULT 0,
start_date datetime DEFAULT NULL,
end_date datetime DEFAULT NULL,
target_categories text,
target_tags text,
is_active tinyint(1) DEFAULT 1,
created_at datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id),
KEY is_active (is_active),
KEY priority (priority)
) $charset_collate;";
// 广告表现表
$sql_ad_performance = "CREATE TABLE IF NOT EXISTS $table_name_ad_performance (
id mediumint(9) NOT NULL AUTO_INCREMENT,
ad_id mediumint(9) NOT NULL,
date date NOT NULL,
impressions int(11) DEFAULT 0,
clicks int(11) DEFAULT 0,
revenue decimal(10,2) DEFAULT 0.00,
hour_of_day tinyint(2) DEFAULT NULL,
user_segment varchar(100) DEFAULT NULL,
page_category varchar(100) DEFAULT NULL,
PRIMARY KEY (id),
KEY ad_id (ad_id),
KEY date (date),
KEY user_segment (user_segment),
UNIQUE KEY unique_record (ad_id, date, hour_of_day, user_segment)
) $charset_collate;";
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
dbDelta($sql_ad_inventory);
dbDelta($sql_ad_performance);
}
/**
* 设置默认插件选项
*/
private function set_default_options() {
$default_options = array(
'allocation_algorithm' => 'weighted_random',
'enable_ai_predictions' => false,
'default_ad_priority' => 5,
'impression_weight' => 0.6,
'click_weight' => 0.3,
'revenue_weight' => 0.1,
'session_duration_weight' => 0.2,
'refresh_interval_minutes' => 30,
'enable_user_segmentation' => true,
'segmentation_criteria' => array('device', 'location', 'behavior'),
'fallback_ad_id' => 0,
'enable_ab_testing' => true,
'test_traffic_percentage' => 10
);
add_option('faa_plugin_settings', $default_options);
}
?>
四、动态分配算法实现
核心的动态分配算法根据多个因素计算广告权重:
<?php
/**
* 动态广告分配算法
* @param array $available_ads 可用广告数组
* @param array $context 当前上下文信息(用户、页面等)
* @return int 选中的广告ID
*/
public function select_ad_dynamically($available_ads, $context = array()) {
global $wpdb;
// 如果没有可用广告,返回0
if (empty($available_ads)) {
return 0;
}
// 获取插件设置
$settings = get_option('faa_plugin_settings');
// 计算每个广告的得分
$ad_scores = array();
$total_score = 0;
foreach ($available_ads as $ad) {
$score = $this->calculate_ad_score($ad, $context, $settings);
$ad_scores[$ad->id] = $score;
$total_score += $score;
}
// 如果总分是0,使用等权重分配
if ($total_score <= 0) {
return $this->select_random_ad($available_ads);
}
// 根据算法类型选择广告
switch ($settings['allocation_algorithm']) {
case 'weighted_random':
return $this->weighted_random_selection($ad_scores, $total_score);
case 'highest_score':
arsort($ad_scores);
return key($ad_scores);
case 'round_robin':
return $this->round_robin_selection($available_ads);
default:
return $this->weighted_random_selection($ad_scores, $total_score);
}
}
/**
* 计算单个广告得分
* @param object $ad 广告对象
* @param array $context 上下文信息
* @param array $settings 插件设置
* @return float 广告得分
*/
private function calculate_ad_score($ad, $context, $settings) {
$score = 0;
// 基础优先级得分
$score += ($ad->priority * 10);
// 获取最近表现数据
$performance = $this->get_ad_performance($ad->id, 7); // 最近7天
if ($performance) {
// CTR得分
$ctr = ($performance->impressions > 0) ?
($performance->clicks / $performance->impressions) : 0;
$score += ($ctr * 1000 * $settings['click_weight']);
// RPM得分(每千次展示收入)
$rpm = ($performance->impressions > 0) ?
($performance->revenue / $performance->impressions * 1000) : 0;
$score += ($rpm * $settings['revenue_weight']);
}
// 时间相关性得分
$score += $this->calculate_time_relevance($ad, $context);
// 内容相关性得分
$score += $this->calculate_content_relevance($ad, $context);
// 用户匹配得分
$score += $this->calculate_user_match($ad, $context);
// 确保每日上限不被超过
if ($ad->daily_cap > 0) {
$today_impressions = $this->get_today_impressions($ad->id);
if ($today_impressions >= $ad->daily_cap) {
$score = 0; // 超过上限,得分为0
} else {
// 接近上限时降低权重
$cap_ratio = $today_impressions / $ad->daily_cap;
if ($cap_ratio > 0.8) {
$score *= (1 - $cap_ratio);
}
}
}
return max(0, $score); // 确保非负
}
/**
* 加权随机选择算法
* @param array $ad_scores 广告得分数组
* @param float $total_score 总得分
* @return int 选中的广告ID
*/
private function weighted_random_selection($ad_scores, $total_score) {
$random_point = mt_rand() / mt_getrandmax() * $total_score;
$current_point = 0;
foreach ($ad_scores as $ad_id => $score) {
$current_point += $score;
if ($current_point >= $random_point) {
return $ad_id;
}
}
// 如果由于浮点精度问题没有返回,返回第一个广告
return key($ad_scores);
}
?>
五、管理界面开发
创建用户友好的管理界面来配置广告和查看数据:
<?php
/**
* 添加管理菜单
*/
public function add_admin_menu() {
// 主菜单
add_menu_page(
'柔性广告分配',
'广告分配',
'manage_options',
'flexible-ad-allocation',
array($this, 'render_main_page'),
'dashicons-chart-area',
30
);
// 子菜单
add_submenu_page(
'flexible-ad-allocation',
'广告库存管理',
'广告库存',
'manage_options',
'faa-ad-inventory',
array($this, 'render_inventory_page')
);
add_submenu_page(
'flexible-ad-allocation',
'性能分析',
'性能分析',
'manage_options',
'faa-analytics',
array($this, 'render_analytics_page')
);
add_submenu_page(
'flexible-ad-allocation',
'插件设置',
'设置',
'manage_options',
'faa-settings',
array($this, 'render_settings_page')
);
}
/**
* 渲染广告库存管理页面
*/
public function render_inventory_page() {
// 检查权限
if (!current_user_can('manage_options')) {
wp_die('权限不足');
}
// 处理表单提交
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['faa_nonce'])) {
if (wp_verify_nonce($_POST['faa_nonce'], 'faa_save_ad')) {
$this->save_ad_inventory($_POST);
echo '<div class="notice notice-success"><p>广告已保存!</p></div>';
}
}
// 获取所有广告
global $wpdb;
$table_name = $wpdb->prefix . 'faa_ad_inventory';
$ads = $wpdb->get_results("SELECT * FROM $table_name ORDER BY priority DESC, created_at DESC");
?>
<div class="wrap">
<h1>广告库存管理</h1>
<div class="faa-admin-container">
<div class="faa-admin-col">
<h2>添加新广告</h2>
<form method="post" action="">
<?php wp_nonce_field('faa_save_ad', 'faa_nonce'); ?>
<table class="form-table">
<tr>
<th><label for="ad_name">广告名称</label></th>
<td><input type="text" id="ad_name" name="ad_name" class="regular-text" required></td>
</tr>
<tr>
<th><label for="ad_code">广告代码</label></th>
<td><textarea id="ad_code" name="ad_code" rows="5" class="large-text" required></textarea></td>
</tr>
<tr>
<th><label for="ad_type">广告类型</label></th>
<td>
<select id="ad_type" name="ad_type">
<option value="banner">横幅广告</option>
<option value="interstitial">插页广告</option>
<option value="native">原生广告</option>
<option value="video">视频广告</option>
</select>
</td>
</tr>
<tr>
<th><label for="priority">优先级 (1-10)</label></th>
<td><input type="number" id="priority" name="priority" min="1" max="10" value="5"></td>
</tr>
<tr>
<th><label for="daily_cap">每日展示上限</label></th>
<td><input type="number" id="daily_cap" name="daily_cap" min="0" value="0"> (0表示无限制)</td>
</tr>
</table>
<p class="submit">
<input type="submit" name="submit" id="submit" class="button button-primary" value="保存广告">
</p>
</form>
</div>
<div class="faa-admin-col">
<h2>现有广告</h2>
<table class="wp-list-table widefat fixed striped">
<thead>
<tr>
<th>ID</th>
<th>广告名称</th>
<th>类型</th>
<th>优先级</th>
<th>今日展示</th>
<th>总展示</th>
<th>状态</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<?php if (empty($ads)): ?>
<tr>
<td colspan="8">暂无广告</td>
</tr>
<?php else: ?>
<?php foreach ($ads as $ad): ?>
<?php $today_impressions = $this->get_today_impressions($ad->id); ?>
<tr>
<td><?php echo $ad->id; ?></td>
<td><?php echo esc_html($ad->ad_name); ?></td>
<td><?php echo esc_html($ad->ad_type); ?></td>
<td><?php echo $ad->priority; ?></td>
<td><?php echo $today_impressions; ?></td>
<td><?php echo $ad->total_impressions; ?></td>
<td>
<span class="faa-status-indicator <?php echo $ad->is_active ? 'active' : 'inactive'; ?>">
<?php echo $ad->is_active ? '活跃' : '暂停'; ?>
</span>
</td>
<td>
<a href="#" class="button faa-toggle-status" data-ad-id="<?php echo $ad->id; ?>">
<?php echo $ad->is_active ? '暂停' : '激活'; ?>
</a>
<a href="#" class="button button-secondary faa-edit-ad" data-ad-id="<?php echo $ad->id; ?>">编辑</a>
</td>
</tr>
<?php endforeach; ?>
<?php endif; ?>
</tbody>
</table>
</div>
</div>
</div>
<style>
.faa-admin-container {
display: flex;
gap: 20px;
margin-top: 20px;
}
.faa-admin-col {
flex: 1;
background: #fff;
padding: 20px;
border: 1px solid #ccd0d4;
box-shadow: 0 1px 1px rgba(0,0,0,.04);
}
.faa-status-indicator {
padding: 3px 8px;
border-radius: 3px;
font-size: 12px;
font-weight: bold;
}
.faa-status-indicator.active {
background: #d4edda;
color: #155724;
}
.faa-status-indicator.inactive {
background: #f8d7da;
color: #721c24;
}
</style>
<script>
jQuery(document).ready(function($) {
// 切换广告状态
$('.faa-toggle-status').on('click', function(e) {
e.preventDefault();
var adId = $(this).data('ad-id');
var button = $(this);
$.post(ajaxurl, {
action: 'faa_toggle_ad_status',
ad_id: adId,
nonce: '<?php echo wp_create_nonce("faa_toggle_ad"); ?>'
function(response) {
if (response.success) {
location.reload();
} else {
alert('操作失败: ' + response.data);
}
}
);
});
// 编辑广告
$('.faa-edit-ad').on('click', function(e) {
e.preventDefault();
var adId = $(this).data('ad-id');
// 这里可以添加编辑逻辑,例如打开模态框
alert('编辑功能开发中,广告ID: ' + adId);
});
});
</script>
<?php
}
?>
六、前端广告展示与跟踪
实现前端广告展示和用户行为跟踪:
<?php
/**
* 前端广告展示
*/
public function display_dynamic_ad() {
// 只在文章页面显示
if (!is_single()) {
return;
}
// 获取当前上下文信息
$context = $this->get_current_context();
// 获取可用广告
$available_ads = $this->get_available_ads($context);
if (empty($available_ads)) {
return;
}
// 动态选择广告
$selected_ad_id = $this->select_ad_dynamically($available_ads, $context);
if ($selected_ad_id) {
// 获取广告代码
$ad_code = $this->get_ad_code($selected_ad_id);
// 记录展示
$this->record_impression($selected_ad_id, $context);
// 输出广告
echo $this->wrap_ad_code($ad_code, $selected_ad_id, $context);
}
}
/**
* 获取当前上下文信息
* @return array 上下文信息数组
*/
private function get_current_context() {
global $post;
$context = array(
'user_id' => get_current_user_id(),
'post_id' => get_the_ID(),
'categories' => wp_get_post_categories(get_the_ID(), array('fields' => 'names')),
'tags' => wp_get_post_tags(get_the_ID(), array('fields' => 'names')),
'hour_of_day' => (int) date('G'),
'day_of_week' => (int) date('w'),
'user_agent' => $_SERVER['HTTP_USER_AGENT'],
'referrer' => isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '',
'device_type' => $this->detect_device_type(),
'session_id' => $this->get_session_id(),
'page_type' => $this->get_page_type()
);
// 添加用户行为数据(如果可用)
if ($context['user_id']) {
$context['user_segment'] = $this->get_user_segment($context['user_id']);
}
return $context;
}
/**
* 获取可用广告列表
* @param array $context 上下文信息
* @return array 可用广告数组
*/
private function get_available_ads($context) {
global $wpdb;
$table_name = $wpdb->prefix . 'faa_ad_inventory';
$current_time = current_time('mysql');
// 基础查询:活跃、在时间范围内的广告
$query = $wpdb->prepare(
"SELECT * FROM $table_name
WHERE is_active = 1
AND (start_date IS NULL OR start_date <= %s)
AND (end_date IS NULL OR end_date >= %s)",
$current_time,
$current_time
);
$ads = $wpdb->get_results($query);
// 过滤不符合条件的广告
$filtered_ads = array();
foreach ($ads as $ad) {
if ($this->is_ad_eligible($ad, $context)) {
$filtered_ads[] = $ad;
}
}
return $filtered_ads;
}
/**
* 检查广告是否符合展示条件
* @param object $ad 广告对象
* @param array $context 上下文信息
* @return bool 是否符合条件
*/
private function is_ad_eligible($ad, $context) {
// 检查每日上限
if ($ad->daily_cap > 0) {
$today_impressions = $this->get_today_impressions($ad->id);
if ($today_impressions >= $ad->daily_cap) {
return false;
}
}
// 检查分类匹配
if (!empty($ad->target_categories)) {
$target_categories = unserialize($ad->target_categories);
if (!empty($target_categories) && !array_intersect($target_categories, $context['categories'])) {
return false;
}
}
// 检查标签匹配
if (!empty($ad->target_tags)) {
$target_tags = unserialize($ad->target_tags);
if (!empty($target_tags) && !array_intersect($target_tags, $context['tags'])) {
return false;
}
}
// 检查设备类型
$device_restrictions = $this->get_ad_device_restrictions($ad->id);
if (!empty($device_restrictions) && !in_array($context['device_type'], $device_restrictions)) {
return false;
}
return true;
}
/**
* 包装广告代码,添加跟踪功能
* @param string $ad_code 原始广告代码
* @param int $ad_id 广告ID
* @param array $context 上下文信息
* @return string 包装后的广告代码
*/
private function wrap_ad_code($ad_code, $ad_id, $context) {
$wrapper_id = 'faa-ad-' . $ad_id . '-' . uniqid();
$wrapped_code = '
<div id="' . esc_attr($wrapper_id) . '" class="faa-dynamic-ad" data-ad-id="' . esc_attr($ad_id) . '">
' . $ad_code . '
<div class="faa-ad-label">广告</div>
</div>
<script>
(function() {
var adElement = document.getElementById("' . esc_js($wrapper_id) . '");
var startTime = Date.now();
var isVisible = false;
// 检查广告是否在视口中
function checkVisibility() {
var rect = adElement.getBoundingClientRect();
var windowHeight = window.innerHeight || document.documentElement.clientHeight;
var windowWidth = window.innerWidth || document.documentElement.clientWidth;
var isInViewport = rect.top >= 0 &&
rect.left >= 0 &&
rect.bottom <= windowHeight &&
rect.right <= windowWidth;
if (isInViewport && !isVisible) {
isVisible = true;
recordViewTime();
} else if (!isInViewport && isVisible) {
isVisible = false;
}
}
// 记录广告观看时间
function recordViewTime() {
var viewTime = Date.now() - startTime;
// 如果观看时间超过1秒,记录为有效展示
if (viewTime >= 1000) {
jQuery.post("' . admin_url('admin-ajax.php') . '", {
action: "faa_record_view_time",
ad_id: ' . intval($ad_id) . ',
view_time: viewTime,
nonce: "' . wp_create_nonce('faa_tracking') . '"
});
}
}
// 点击跟踪
adElement.addEventListener("click", function(e) {
// 检查点击的是否是广告链接
if (e.target.tagName === "A" || e.target.closest("a")) {
jQuery.post("' . admin_url('admin-ajax.php') . '", {
action: "faa_record_click",
ad_id: ' . intval($ad_id) . ',
nonce: "' . wp_create_nonce('faa_tracking') . '"
});
}
});
// 滚动时检查可见性
window.addEventListener("scroll", checkVisibility);
window.addEventListener("resize", checkVisibility);
// 初始检查
setTimeout(checkVisibility, 500);
// 页面卸载时记录最后观看时间
window.addEventListener("beforeunload", function() {
if (isVisible) {
recordViewTime();
}
});
})();
</script>
<style>
.faa-dynamic-ad {
position: relative;
margin: 20px 0;
border: 1px solid #e0e0e0;
border-radius: 4px;
overflow: hidden;
}
.faa-ad-label {
position: absolute;
top: 5px;
right: 5px;
background: rgba(0,0,0,0.7);
color: white;
font-size: 10px;
padding: 2px 6px;
border-radius: 2px;
z-index: 10;
}
</style>';
return $wrapped_code;
}
/**
* 记录广告展示
* @param int $ad_id 广告ID
* @param array $context 上下文信息
*/
private function record_impression($ad_id, $context) {
global $wpdb;
$table_name = $wpdb->prefix . 'faa_ad_performance';
$current_date = current_time('Y-m-d');
// 检查是否已有今日记录
$existing_record = $wpdb->get_row($wpdb->prepare(
"SELECT id, impressions FROM $table_name
WHERE ad_id = %d AND date = %s AND hour_of_day = %d AND user_segment = %s",
$ad_id,
$current_date,
$context['hour_of_day'],
$context['user_segment'] ?? 'unknown'
));
if ($existing_record) {
// 更新现有记录
$wpdb->update(
$table_name,
array('impressions' => $existing_record->impressions + 1),
array('id' => $existing_record->id)
);
} else {
// 创建新记录
$wpdb->insert(
$table_name,
array(
'ad_id' => $ad_id,
'date' => $current_date,
'impressions' => 1,
'hour_of_day' => $context['hour_of_day'],
'user_segment' => $context['user_segment'] ?? 'unknown',
'page_category' => !empty($context['categories']) ? $context['categories'][0] : 'uncategorized'
)
);
}
// 更新广告总展示数
$inventory_table = $wpdb->prefix . 'faa_ad_inventory';
$wpdb->query($wpdb->prepare(
"UPDATE $inventory_table SET total_impressions = total_impressions + 1 WHERE id = %d",
$ad_id
));
}
?>
七、AJAX处理与数据统计
实现AJAX处理和数据统计功能:
<?php
/**
* 初始化AJAX处理
*/
private function init_ajax_handlers() {
// 前端跟踪
add_action('wp_ajax_faa_record_click', array($this, 'ajax_record_click'));
add_action('wp_ajax_nopriv_faa_record_click', array($this, 'ajax_record_click'));
add_action('wp_ajax_faa_record_view_time', array($this, 'ajax_record_view_time'));
add_action('wp_ajax_nopriv_faa_record_view_time', array($this, 'ajax_record_view_time'));
// 管理功能
add_action('wp_ajax_faa_toggle_ad_status', array($this, 'ajax_toggle_ad_status'));
add_action('wp_ajax_faa_get_ad_stats', array($this, 'ajax_get_ad_stats'));
add_action('wp_ajax_faa_get_performance_report', array($this, 'ajax_get_performance_report'));
}
/**
* AJAX记录点击
*/
public function ajax_record_click() {
// 验证nonce
if (!wp_verify_nonce($_POST['nonce'], 'faa_tracking')) {
wp_die('安全验证失败');
}
$ad_id = intval($_POST['ad_id']);
if ($ad_id) {
global $wpdb;
$table_name = $wpdb->prefix . 'faa_ad_performance';
$current_date = current_time('Y-m-d');
$hour_of_day = (int) date('G');
// 查找现有记录
$existing_record = $wpdb->get_row($wpdb->prepare(
"SELECT id, clicks FROM $table_name
WHERE ad_id = %d AND date = %s AND hour_of_day = %d",
$ad_id,
$current_date,
$hour_of_day
));
if ($existing_record) {
// 更新现有记录
$wpdb->update(
$table_name,
array('clicks' => $existing_record->clicks + 1),
array('id' => $existing_record->id)
);
} else {
// 创建新记录
$wpdb->insert(
$table_name,
array(
'ad_id' => $ad_id,
'date' => $current_date,
'clicks' => 1,
'hour_of_day' => $hour_of_day
)
);
}
// 更新广告总点击量
$inventory_table = $wpdb->prefix . 'faa_ad_inventory';
$wpdb->query($wpdb->prepare(
"UPDATE $inventory_table SET total_clicks = total_clicks + 1 WHERE id = %d",
$ad_id
));
wp_send_json_success('点击已记录');
}
wp_send_json_error('无效的广告ID');
}
/**
* 获取广告统计数据
*/
public function ajax_get_ad_stats() {
// 验证权限
if (!current_user_can('manage_options')) {
wp_send_json_error('权限不足');
}
$ad_id = intval($_POST['ad_id']);
$period = sanitize_text_field($_POST['period'] ?? '7days');
global $wpdb;
$performance_table = $wpdb->prefix . 'faa_ad_performance';
// 根据时间段构建查询
switch ($period) {
case 'today':
$date_condition = "date = CURDATE()";
break;
case '7days':
$date_condition = "date >= DATE_SUB(CURDATE(), INTERVAL 7 DAY)";
break;
case '30days':
$date_condition = "date >= DATE_SUB(CURDATE(), INTERVAL 30 DAY)";
break;
default:
$date_condition = "date >= DATE_SUB(CURDATE(), INTERVAL 7 DAY)";
}
// 获取统计数据
$stats = $wpdb->get_row($wpdb->prepare(
"SELECT
SUM(impressions) as total_impressions,
SUM(clicks) as total_clicks,
SUM(revenue) as total_revenue,
AVG(CASE WHEN impressions > 0 THEN clicks/impressions ELSE 0 END) as avg_ctr,
AVG(CASE WHEN impressions > 0 THEN revenue/impressions*1000 ELSE 0 END) as avg_rpm
FROM $performance_table
WHERE ad_id = %d AND $date_condition",
$ad_id
));
// 获取按小时分布数据
$hourly_data = $wpdb->get_results($wpdb->prepare(
"SELECT
hour_of_day,
SUM(impressions) as impressions,
SUM(clicks) as clicks,
AVG(CASE WHEN impressions > 0 THEN clicks/impressions ELSE 0 END) as ctr
FROM $performance_table
WHERE ad_id = %d AND $date_condition
GROUP BY hour_of_day
ORDER BY hour_of_day",
$ad_id
));
// 获取用户分群数据
$segment_data = $wpdb->get_results($wpdb->prepare(
"SELECT
user_segment,
SUM(impressions) as impressions,
SUM(clicks) as clicks,
AVG(CASE WHEN impressions > 0 THEN clicks/impressions ELSE 0 END) as ctr
FROM $performance_table
WHERE ad_id = %d AND $date_condition AND user_segment != 'unknown'
GROUP BY user_segment
ORDER BY impressions DESC
LIMIT 5",
$ad_id
));
$response = array(
'stats' => $stats,
'hourly_data' => $hourly_data,
'segment_data' => $segment_data,
'period' => $period
);
wp_send_json_success($response);
}
/**
* 渲染数据分析页面
*/
public function render_analytics_page() {
?>
<div class="wrap">
<h1>广告性能分析</h1>
<div class="faa-analytics-container">
<div class="faa-analytics-header">
<div class="faa-period-selector">
<label for="analytics-period">时间段:</label>
<select id="analytics-period">
<option value="today">今日</option>
<option value="7days" selected>最近7天</option>
<option value="30days">最近30天</option>
<option value="custom">自定义</option>
</select>
<div id="custom-period" style="display:none; margin-left:10px;">
<input type="date" id="start-date">
<span>至</span>
<input type="date" id="end-date">
<button id="apply-custom-period" class="button">应用</button>
</div>
</div>
<div class="faa-ad-selector">
<label for="analytics-ad">选择广告:</label>
<select id="analytics-ad">
<option value="all">所有广告</option>
<?php
