文章目录
-
- 在当今数字化营销时代,网络传媒平台需要更智能的广告管理解决方案。本教程将指导您开发一个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
在当今数字化营销时代,网络传媒平台需要更智能的广告管理解决方案。本教程将指导您开发一个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


