WordPress网络传媒柔性广告智能竞价插件开发教程
一、插件概述与设计思路
在当今数字化营销时代,网络传媒平台需要更智能的广告管理解决方案。本教程将指导您开发一个WordPress柔性广告智能竞价插件,该插件能够根据广告位表现、用户行为和实时数据自动调整广告竞价策略。
核心功能设计:
- 多广告位智能管理
- 基于机器学习的竞价算法
- 实时性能监控与调整
- A/B测试框架
- 详细数据报表
二、插件基础结构搭建
首先创建插件的基本文件结构:
<?php
/**
* Plugin Name: 柔性广告智能竞价系统
* Plugin URI: https://yourwebsite.com/
* Description: 基于AI的WordPress广告智能竞价管理插件
* Version: 1.0.0
* Author: 您的名称
* License: GPL v2 or later
*/
// 防止直接访问
if (!defined('ABSPATH')) {
exit;
}
// 定义插件常量
define('FLEX_AD_BIDDING_VERSION', '1.0.0');
define('FLEX_AD_BIDDING_PLUGIN_DIR', plugin_dir_path(__FILE__));
define('FLEX_AD_BIDDING_PLUGIN_URL', plugin_dir_url(__FILE__));
// 初始化插件
class FlexAdBidding_Init {
public function __construct() {
$this->init_hooks();
$this->include_files();
}
// 注册WordPress钩子
private function init_hooks() {
register_activation_hook(__FILE__, array($this, 'activate_plugin'));
register_deactivation_hook(__FILE__, array($this, 'deactivate_plugin'));
add_action('admin_menu', array($this, 'create_admin_menu'));
add_action('admin_enqueue_scripts', array($this, 'enqueue_admin_scripts'));
}
// 包含必要文件
private function include_files() {
require_once FLEX_AD_BIDDING_PLUGIN_DIR . 'includes/class-ad-manager.php';
require_once FLEX_AD_BIDDING_PLUGIN_DIR . 'includes/class-bidding-algorithm.php';
require_once FLEX_AD_BIDDING_PLUGIN_DIR . 'includes/class-analytics.php';
}
// 插件激活时创建数据库表
public function activate_plugin() {
global $wpdb;
$charset_collate = $wpdb->get_charset_collate();
$table_name = $wpdb->prefix . 'flex_ad_bidding_data';
$sql = "CREATE TABLE IF NOT EXISTS $table_name (
id mediumint(9) NOT NULL AUTO_INCREMENT,
ad_position varchar(100) NOT NULL,
impression_count int DEFAULT 0,
click_count int DEFAULT 0,
current_bid decimal(10,2) DEFAULT 0.00,
performance_score decimal(5,4) DEFAULT 0.0000,
created_at datetime DEFAULT CURRENT_TIMESTAMP,
updated_at datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id),
INDEX ad_position_idx (ad_position)
) $charset_collate;";
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
dbDelta($sql);
// 创建默认配置
add_option('flex_ad_bidding_settings', array(
'auto_bidding' => true,
'max_bid_limit' => 5.00,
'learning_rate' => 0.01,
'performance_threshold' => 0.5
));
}
// 插件停用时的清理工作
public function deactivate_plugin() {
// 可选的清理代码
// 注意:通常不删除数据,以便用户重新激活时保留设置
}
// 创建管理菜单
public function create_admin_menu() {
add_menu_page(
'柔性广告竞价',
'广告竞价',
'manage_options',
'flex-ad-bidding',
array($this, 'admin_dashboard'),
'dashicons-chart-line',
30
);
add_submenu_page(
'flex-ad-bidding',
'广告位管理',
'广告位',
'manage_options',
'flex-ad-positions',
array($this, 'ad_positions_page')
);
add_submenu_page(
'flex-ad-bidding',
'竞价设置',
'设置',
'manage_options',
'flex-ad-settings',
array($this, 'settings_page')
);
}
// 加载管理端脚本和样式
public function enqueue_admin_scripts($hook) {
if (strpos($hook, 'flex-ad') !== false) {
wp_enqueue_style('flex-ad-admin-style',
FLEX_AD_BIDDING_PLUGIN_URL . 'assets/css/admin-style.css');
wp_enqueue_script('flex-ad-admin-script',
FLEX_AD_BIDDING_PLUGIN_URL . 'assets/js/admin-script.js',
array('jquery', 'chartjs'), FLEX_AD_BIDDING_VERSION, true);
// 本地化脚本,传递数据到JavaScript
wp_localize_script('flex-ad-admin-script', 'flexAdData', array(
'ajax_url' => admin_url('admin-ajax.php'),
'nonce' => wp_create_nonce('flex_ad_nonce')
));
}
}
// 管理仪表板
public function admin_dashboard() {
include FLEX_AD_BIDDING_PLUGIN_DIR . 'templates/admin-dashboard.php';
}
public function ad_positions_page() {
include FLEX_AD_BIDDING_PLUGIN_DIR . 'templates/ad-positions.php';
}
public function settings_page() {
include FLEX_AD_BIDDING_PLUGIN_DIR . 'templates/settings.php';
}
}
// 初始化插件
new FlexAdBidding_Init();
?>
三、智能竞价算法实现
下面是核心的智能竞价算法类:
<?php
/**
* 智能竞价算法类
* 使用机器学习方法动态调整广告竞价
*/
class FlexAdBidding_Algorithm {
private $learning_rate;
private $exploration_rate;
private $max_bid;
public function __construct() {
$settings = get_option('flex_ad_bidding_settings');
$this->learning_rate = $settings['learning_rate'] ?? 0.01;
$this->exploration_rate = 0.1; // 10%的探索率
$this->max_bid = $settings['max_bid_limit'] ?? 5.00;
}
/**
* 计算智能竞价
* @param string $ad_position 广告位ID
* @param array $context 上下文信息(用户设备、时间等)
* @return float 建议竞价
*/
public function calculate_bid($ad_position, $context = array()) {
global $wpdb;
// 获取历史数据
$table_name = $wpdb->prefix . 'flex_ad_bidding_data';
$history = $wpdb->get_row($wpdb->prepare(
"SELECT * FROM $table_name WHERE ad_position = %s ORDER BY updated_at DESC LIMIT 1",
$ad_position
));
// 基础竞价
$base_bid = $history ? $history->current_bid : 0.50;
// 计算性能得分
$performance_score = $this->calculate_performance_score($ad_position);
// 上下文调整因子
$context_factor = $this->calculate_context_factor($context);
// 探索与利用策略
if (mt_rand(1, 100) <= ($this->exploration_rate * 100)) {
// 探索:随机调整竞价以发现新机会
$random_factor = mt_rand(80, 120) / 100;
$new_bid = $base_bid * $random_factor;
} else {
// 利用:基于历史表现调整
$adjustment = $performance_score * $this->learning_rate * $context_factor;
$new_bid = $base_bid * (1 + $adjustment);
}
// 应用限制
$new_bid = max(0.10, min($this->max_bid, $new_bid));
// 更新数据库
$this->update_bid_history($ad_position, $new_bid, $performance_score);
return round($new_bid, 2);
}
/**
* 计算广告位性能得分
* @param string $ad_position 广告位ID
* @return float 性能得分(0-1)
*/
private function calculate_performance_score($ad_position) {
global $wpdb;
$table_name = $wpdb->prefix . 'flex_ad_bidding_data';
// 获取最近7天的数据
$seven_days_ago = date('Y-m-d H:i:s', strtotime('-7 days'));
$results = $wpdb->get_results($wpdb->prepare(
"SELECT impression_count, click_count FROM $table_name
WHERE ad_position = %s AND created_at >= %s",
$ad_position, $seven_days_ago
));
$total_impressions = 0;
$total_clicks = 0;
foreach ($results as $row) {
$total_impressions += $row->impression_count;
$total_clicks += $row->click_count;
}
// 计算点击率
$ctr = $total_impressions > 0 ? $total_clicks / $total_impressions : 0;
// 归一化处理(假设行业平均CTR为0.5%)
$normalized_ctr = min(1, $ctr / 0.005);
return $normalized_ctr;
}
/**
* 计算上下文调整因子
* @param array $context 上下文信息
* @return float 调整因子
*/
private function calculate_context_factor($context) {
$factor = 1.0;
// 时间因素(假设晚上效果更好)
$hour = date('H');
if ($hour >= 18 && $hour <= 23) {
$factor *= 1.2; // 晚上提高20%
} elseif ($hour >= 0 && $hour <= 6) {
$factor *= 0.8; // 凌晨降低20%
}
// 设备因素
if (isset($context['device'])) {
if ($context['device'] === 'mobile') {
$factor *= 1.15; // 移动端提高15%
} elseif ($context['device'] === 'tablet') {
$factor *= 1.05; // 平板提高5%
}
}
// 用户类型(新用户/老用户)
if (isset($context['user_type'])) {
if ($context['user_type'] === 'new') {
$factor *= 1.1; // 新用户提高10%
}
}
return $factor;
}
/**
* 更新竞价历史
*/
private function update_bid_history($ad_position, $new_bid, $performance_score) {
global $wpdb;
$table_name = $wpdb->prefix . 'flex_ad_bidding_data';
$wpdb->insert($table_name, array(
'ad_position' => $ad_position,
'current_bid' => $new_bid,
'performance_score' => $performance_score,
'created_at' => current_time('mysql')
));
}
/**
* A/B测试:比较两种竞价策略
* @param string $ad_position 广告位ID
* @param float $bid_a 策略A竞价
* @param float $bid_b 策略B竞价
* @return array 测试结果
*/
public function run_ab_test($ad_position, $bid_a, $bid_b) {
// 随机分配用户到A组或B组
$group = (mt_rand(1, 100) <= 50) ? 'A' : 'B';
$test_bid = ($group === 'A') ? $bid_a : $bid_b;
// 记录测试分配
$this->log_ab_test($ad_position, $group, $test_bid);
return array(
'group' => $group,
'bid' => $test_bid,
'test_id' => uniqid('abtest_')
);
}
}
?>
四、前端广告展示与追踪
创建前端广告展示短代码和追踪系统:
<?php
/**
* 前端广告展示类
*/
class FlexAdBidding_Display {
private $algorithm;
public function __construct() {
$this->algorithm = new FlexAdBidding_Algorithm();
add_shortcode('flex_ad', array($this, 'render_ad_shortcode'));
add_action('wp_footer', array($this, 'add_tracking_script'));
}
/**
* 广告展示短代码
* 用法:[flex_ad position="header" width="728" height="90"]
*/
public function render_ad_shortcode($atts) {
$atts = shortcode_atts(array(
'position' => 'default',
'width' => '728',
'height' => '90',
'fallback_image' => ''
), $atts);
// 获取智能竞价
$context = $this->get_user_context();
$bid_amount = $this->algorithm->calculate_bid($atts['position'], $context);
// 获取广告内容
$ad_content = $this->get_ad_content($atts['position'], $bid_amount);
// 生成唯一ID用于追踪
$ad_id = 'flex_ad_' . $atts['position'] . '_' . uniqid();
// 记录展示
$this->record_impression($atts['position'], $ad_id, $bid_amount);
// 构建广告HTML
$html = '<div class="flex-ad-container" id="' . esc_attr($ad_id) . '"
data-ad-position="' . esc_attr($atts['position']) . '"
data-ad-bid="' . esc_attr($bid_amount) . '">';
$html .= '<div class="flex-ad-content">';
$html .= $ad_content;
$html .= '</div>';
// 添加追踪像素
$html .= '<img src="' . admin_url('admin-ajax.php') .
'?action=flex_ad_tracking&type=impression&ad_id=' . $ad_id .
'" style="display:none;" width="1" height="1" alt="">';
$html .= '</div>';
// 添加内联样式
$html .= '<style>
.flex-ad-container {
width: ' . intval($atts['width']) . 'px;
height: ' . intval($atts['height']) . 'px;
position: relative;
margin: 10px auto;
border: 1px solid #eee;
}
.flex-ad-content {
width: 100%;
height: 100%;
overflow: hidden;
}
</style>';
return $html;
}
/**
* 获取用户上下文信息
*/
private function get_user_context() {
$context = array();
// 检测设备类型
$context['device'] = wp_is_mobile() ? 'mobile' : 'desktop';
// 用户类型(简化示例)
$context['user_type'] = is_user_logged_in() ? 'returning' : 'new';
// 页面类型
if (is_single()) {
$context['page_type'] = 'single';
} elseif (is_page()) {
$context['page_type'] = 'page';
} elseif (is_home()) {
$context['page_type'] = 'home';
} else {
$context['page_type'] = 'other';
}
return $context;
}
/**
* 获取广告内容
*/
private function get_ad_content($position, $bid_amount) {
// 这里可以连接广告联盟API或使用本地广告库
// 简化示例:返回模拟广告
$ad_templates = array(
'<div class="ad-template" style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 20px; text-align: center;">
<h3 style="margin: 0 0 10px 0;">智能推荐广告</h3>
<p>基于AI竞价: $' . $bid_amount . '</p>
<a href="#" class="ad-click-trigger" style="background: white; color: #667eea; padding: 8px 15px; border-radius: 4px; text-decoration: none; display: inline-block; margin-top: 10px;">了解更多</a>
</div>',
'<div class="ad-template" style="background: #f8f9fa; border-left: 4px solid #28a745; padding: 15px;">
<h4 style="margin: 0 0 8px 0;">精选推荐</h4>
<p style="margin: 0 0 10px 0; color: #666;">优化竞价: $' . $bid_amount . '</p>
<button class="ad-click-trigger" style="background: #28a745; color: white; border: none; padding: 6px 12px; border-radius: 3px; cursor: pointer;">查看详情</button>
</div>'
);
// 根据广告位选择模板
$template_index = array_rand($ad_templates);
return $ad_templates[$template_index];
}
/**
* 记录广告展示
*/
bid_amount) {
global $wpdb;
$table_name = $wpdb->prefix . 'flex_ad_bidding_data';
// 更新展示次数
$wpdb->query($wpdb->prepare(
"UPDATE $table_name
SET impression_count = impression_count + 1
WHERE ad_position = %s
ORDER BY created_at DESC LIMIT 1",
$position
));
// 存储会话数据用于点击追踪
if (!isset($_SESSION['flex_ad_impressions'])) {
$_SESSION['flex_ad_impressions'] = array();
}
$_SESSION['flex_ad_impressions'][$ad_id] = array(
'position' => $position,
'bid_amount' => $bid_amount,
'timestamp' => time()
);
}
/**
* 添加前端追踪脚本
*/
public function add_tracking_script() {
?>
<script type="text/javascript">
(function($) {
'use strict';
// 广告点击追踪
$(document).on('click', '.ad-click-trigger', function(e) {
e.preventDefault();
var $adContainer = $(this).closest('.flex-ad-container');
var adId = $adContainer.attr('id');
var adPosition = $adContainer.data('ad-position');
// 发送点击追踪请求
$.ajax({
url: flexAdData.ajax_url,
type: 'POST',
data: {
action: 'flex_ad_track_click',
ad_id: adId,
position: adPosition,
nonce: flexAdData.nonce
},
success: function(response) {
if (response.success) {
// 点击记录成功,可以跳转链接
window.location.href = $(e.target).closest('a').attr('href') || '#';
}
}
});
});
// 广告可视性追踪
var adVisibilityTracker = function() {
$('.flex-ad-container').each(function() {
var $ad = $(this);
var isVisible = isElementInViewport($ad[0]);
if (isVisible && !$ad.data('view-tracked')) {
$ad.data('view-tracked', true);
// 发送可视性追踪
$.post(flexAdData.ajax_url, {
action: 'flex_ad_track_view',
ad_id: $ad.attr('id'),
position: $ad.data('ad-position'),
nonce: flexAdData.nonce
});
}
});
};
// 检查元素是否在可视区域内
function isElementInViewport(el) {
var rect = el.getBoundingClientRect();
return (
rect.top >= 0 &&
rect.left >= 0 &&
rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
rect.right <= (window.innerWidth || document.documentElement.clientWidth)
);
}
// 滚动时检查广告可视性
$(window).on('scroll resize', adVisibilityTracker);
$(document).ready(adVisibilityTracker);
})(jQuery);
</script>
<?php
}
}
// 初始化前端展示
new FlexAdBidding_Display();
?>
## 五、AJAX处理与数据追踪
创建AJAX处理类来管理数据追踪:
<?php
/**
- AJAX处理与数据追踪类
*/
class FlexAdBidding_Ajax {
public function __construct() {
// 注册AJAX动作
add_action('wp_ajax_flex_ad_track_click', array($this, 'track_click'));
add_action('wp_ajax_nopriv_flex_ad_track_click', array($this, 'track_click'));
add_action('wp_ajax_flex_ad_track_view', array($this, 'track_view'));
add_action('wp_ajax_nopriv_flex_ad_track_view', array($this, 'track_view'));
add_action('wp_ajax_flex_ad_get_stats', array($this, 'get_statistics'));
add_action('wp_ajax_flex_ad_update_settings', array($this, 'update_settings'));
}
/**
* 追踪广告点击
*/
public function track_click() {
// 验证nonce
if (!wp_verify_nonce($_POST['nonce'], 'flex_ad_nonce')) {
wp_die('安全验证失败');
}
$ad_id = sanitize_text_field($_POST['ad_id']);
$position = sanitize_text_field($_POST['position']);
global $wpdb;
$table_name = $wpdb->prefix . 'flex_ad_bidding_data';
// 更新点击次数
$result = $wpdb->query($wpdb->prepare(
"UPDATE $table_name
SET click_count = click_count + 1
WHERE ad_position = %s
ORDER BY created_at DESC LIMIT 1",
$position
));
// 记录详细点击日志
$log_table = $wpdb->prefix . 'flex_ad_clicks_log';
$wpdb->insert($log_table, array(
'ad_id' => $ad_id,
'ad_position' => $position,
'user_ip' => $this->get_user_ip(),
'user_agent' => $_SERVER['HTTP_USER_AGENT'],
'click_time' => current_time('mysql'),
'page_url' => $_SERVER['HTTP_REFERER'] ?? ''
));
// 计算实时CTR并调整竞价
$this->adjust_bid_based_on_performance($position);
wp_send_json_success(array(
'message' => '点击记录成功',
'ad_id' => $ad_id
));
}
/**
* 追踪广告可视性
*/
public function track_view() {
if (!wp_verify_nonce($_POST['nonce'], 'flex_ad_nonce')) {
wp_die('安全验证失败');
}
$ad_id = sanitize_text_field($_POST['ad_id']);
$position = sanitize_text_field($_POST['position']);
// 记录可视性数据(简化示例)
// 在实际应用中,这里可以记录更详细的可视性指标
wp_send_json_success(array(
'message' => '可视性记录成功'
));
}
/**
* 获取统计数据
*/
public function get_statistics() {
global $wpdb;
$table_name = $wpdb->prefix . 'flex_ad_bidding_data';
// 获取总体统计
$stats = $wpdb->get_results("
SELECT
ad_position,
SUM(impression_count) as total_impressions,
SUM(click_count) as total_clicks,
AVG(current_bid) as avg_bid,
AVG(performance_score) as avg_performance
FROM $table_name
GROUP BY ad_position
ORDER BY total_impressions DESC
");
// 获取趋势数据(最近7天)
$seven_days_ago = date('Y-m-d', strtotime('-7 days'));
$trends = $wpdb->get_results($wpdb->prepare("
SELECT
DATE(created_at) as date,
ad_position,
SUM(impression_count) as daily_impressions,
SUM(click_count) as daily_clicks,
AVG(current_bid) as daily_avg_bid
FROM $table_name
WHERE created_at >= %s
GROUP BY DATE(created_at), ad_position
ORDER BY date ASC
", $seven_days_ago));
wp_send_json_success(array(
'stats' => $stats,
'trends' => $trends,
'summary' => $this->calculate_summary_stats($stats)
));
}
/**
* 更新插件设置
*/
public function update_settings() {
if (!current_user_can('manage_options')) {
wp_die('权限不足');
}
$settings = array(
'auto_bidding' => isset($_POST['auto_bidding']) ? true : false,
'max_bid_limit' => floatval($_POST['max_bid_limit']),
'learning_rate' => floatval($_POST['learning_rate']),
'performance_threshold' => floatval($_POST['performance_threshold']),
'exploration_rate' => floatval($_POST['exploration_rate']),
'enable_ab_testing' => isset($_POST['enable_ab_testing']) ? true : false
);
update_option('flex_ad_bidding_settings', $settings);
wp_send_json_success(array(
'message' => '设置更新成功',
'settings' => $settings
));
}
/**
* 根据性能调整竞价
*/
private function adjust_bid_based_on_performance($position) {
global $wpdb;
$table_name = $wpdb->prefix . 'flex_ad_bidding_data';
// 获取最近数据计算CTR
$recent_data = $wpdb->get_row($wpdb->prepare(
"SELECT impression_count, click_count, current_bid
FROM $table_name
WHERE ad_position = %s
ORDER BY created_at DESC LIMIT 1",
$position
));
if ($recent_data && $recent_data->impression_count > 10) {
$ctr = $recent_data->click_count / $recent_data->impression_count;
$settings = get_option('flex_ad_bidding_settings');
// 如果CTR低于阈值,降低竞价
if ($ctr < $settings['performance_threshold']) {
$new_bid = $recent_data->current_bid * 0.9; // 降低10%
$new_bid = max(0.10, $new_bid); // 最低0.10
$wpdb->insert($table_name, array(
'ad_position' => $position,
'current_bid' => $new_bid,
'performance_score' => $ctr,
'created_at' => current_time('mysql')
));
}
}
}
/**
* 计算汇总统计
*/
private function calculate_summary_stats($stats) {
$summary = array(
'total_impressions' => 0,
'total_clicks' => 0,
'total_spend' => 0,
'overall_ctr' => 0
);
foreach ($stats as $stat) {
$summary['total_impressions'] += $stat->total_impressions;
$summary['total_clicks'] += $stat->total_clicks;
$summary['total_spend'] += $stat->total_impressions * $stat->avg_bid / 1000; // CPM计算
}
if ($summary['total_impressions'] > 0) {
$summary['overall_ctr'] = ($summary['total_clicks'] / $summary['total_impressions']) * 100;
}
return $summary;
}
/**
* 获取用户IP
*/
private function get_user_ip() {
$ip = '';
if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
$ip = $_SERVER['HTTP_CLIENT_IP'];
} elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
$ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
} else {
$ip = $_SERVER['REMOTE_ADDR'];
}
return sanitize_text_field($ip);
}
}
// 初始化AJAX处理
new FlexAdBidding_Ajax();
?>
## 六、数据报表与可视化
创建数据报表生成功能:
<?php
/**
- 数据报表与可视化类
*/
class FlexAdBidding_Reports {
public function __construct() {
add_action('admin_init', array($this, 'generate_daily_report'));
add_filter('cron_schedules', array($this, 'add_custom_cron_schedule'));
add_action('flex_ad_daily_report', array($this, 'send_daily_report_email'));
}
/**
* 生成日报表
*/
public function generate_daily_report() {
global $wpdb;
$table_name = $wpdb->prefix . 'flex_ad_bidding_data';
$yesterday = date('Y-m-d', strtotime('-1 day'));
$report_data = $wpdb->get_results($wpdb->prepare("
SELECT
ad_position,
SUM(impression_count) as impressions,
SUM(click_count) as clicks,
AVG(current_bid) as avg_bid,
CASE
WHEN SUM(impression_count) > 0
THEN (SUM(click_count) / SUM(impression_count)) * 100
ELSE 0
END as ctr
FROM $table_name
WHERE DATE(created_at) = %s
GROUP BY ad_position
ORDER BY impressions DESC
", $yesterday));
// 存储日报表数据
update_option('flex_ad_daily_report_' . $yesterday, $report_data);
return $report_data;
}
/**
* 发送日报表邮件
*/
public function send_daily_report_email() {
$report_data = $this->generate_daily_report();
if (empty($report_data)) {
return;
}
$admin_email = get_option('admin_email');
$subject = '柔性广告竞价系统日报表 - ' . date('Y-m-d', strtotime('-1 day'));
// 构建HTML邮件内容
$message = '<html><body>';
$message .= '<h2>广告竞价日报表</h2>';
$message .= '<p>报告日期: ' . date('Y-m-d', strtotime('-1 day')) . '</p>';
$message .= '<table border="1" cellpadding="10" style="border-collapse: collapse;">';
$message .= '<tr style="background-color: #f2f2f2;">
<th>广告位</th>
<th>展示量</th>
<th>点击量</th>
<th>CTR</th>
<th>平均竞价</th>
</tr>';
$total_impressions = 0;
$total_clicks = 0;
foreach ($report_data as $row) {
$message .= '<tr>';
$message .= '<td>' . esc_html($row->ad_position) . '</td>';
$message .= '<td>' . number_format($row->impressions) . '</td>';
$message .= '<td>' . number_format($row->clicks) . '</td>';
$message .= '<td>' . number_format($row->ctr, 2) . '%</td>';
$message .= '<td>$' . number_format($row->avg_bid, 2) . '</td>';
$message .= '</tr>';
$total_impressions += $row->impressions;
$total_clicks += $row->clicks;
}
$overall_ctr = ($total_impressions > 0) ? ($total_clicks / $total_impressions) * 100 : 0;
$message .= '<tr style="background-color: #e8f4fd; font-weight: bold;">';
$message .= '<td>总计</td>';
$message .= '<td>' . number_format($total_impressions) . '</td>';
$message .= '<td>' . number_format($total_clicks) . '</td>';
$message .= '<td>' . number_format($overall_ctr, 2) . '%</td>';
$message .= '<td>-</td>';
$message .= '</tr>';
$message .= '</table>';
$message .= '<p><a href="' . admin_url('admin.php?page=flex-ad-bidding') . '">查看详细报表</a></p>';
$message .= '</body></html>';
// 设置邮件头
$headers = array(
'Content-Type: text/html; charset=UTF-8',
'From: WordPress广告系统 <' . $admin_email . '>'
);
// 发送邮件
wp_mail($admin_email, $subject, $message, $headers);
}
/**
* 添加自定义Cron计划
*/
public function add_custom_cron_schedule($schedules) {
$schedules['daily'] = array(
'interval' => 86400, // 24小时
'display' => __('每日一次')
);
return $schedules;
}
/**
* 生成可视化图表数据
*/
public function generate_chart_data($period = '7days') {
global $wpdb;
$table_name = $wpdb->prefix . 'flex_ad_bidding_data';
switch ($period) {
case '7days':
$date_condition = "created_at >= DATE_SUB(NOW(), INTERVAL 7 DAY)";
break;
case '30days':
$date_condition = "created_at >= DATE_SUB(NOW(), INTERVAL 30 DAY)";
break;
case '90days':
$date_condition = "created_at >= DATE_SUB(NOW(), INTERVAL 90 DAY)";
break;
default:
$date_condition = "created_at >= DATE_SUB(NOW(), INTERVAL 7 DAY)";
}
$chart_data = $wpdb->get_results("
SELECT
DATE(created_at) as date,
SUM(impression_count) as impressions,
SUM(click_count) as clicks,
AVG(current_bid) as avg_bid
FROM $table_name
WHERE $date_condition
GROUP BY DATE(created_at)
ORDER BY date ASC
");
// 格式化数据供Chart.js使用
$formatted_data = array(
'labels' => array(),
'impressions' => array(),
'clicks' => array(),
'ctr' => array(),
'bids' => array
