对客户如何与您的产品互动的深入洞察。通过跟踪展示次数、点击次数和转化次数,您可以了解哪些产品表现最佳,并相应地优化您的目录。
### 主要功能
* **展示次数跟踪**:跟踪每件产品的浏览次数
* **点击跟踪**:通过跟踪产品点击次数来监控用户参与度
* **点击率计算**:计算点击率以识别表现优异的产品
* **转化跟踪**:跟踪产品的购买时间
* **详细报告**:使用可排序的表格和图表查看全面的分析
* **仪表板小部件**:直接在 WordPress 仪表板上快速访问关键指标
相关文章: WooCommerce 尺寸图表插件
<?php /** * Plugin Name: BDFG Product Analytics * Plugin URI: https://beiduofengou.net/2025/01/06/bdfg-product-analytics/ * Description: Premium analytics solution that tracks product impressions, clicks, conversions, and calculates CTR to optimize your product offerings. * Version: 2.1.0 * Author: Bei Duo Feng Ou * Author URI: https://beiduofengou.net * Text Domain: bdfg-product-analytics * Domain Path: /languages * Requires at least: 5.6 * Requires PHP: 7.2 * WC requires at least: 4.0 * WC tested up to: 7.9 * * @package BDFG_Product_Analytics */ // If this file is called directly, abort. if (!defined('ABSPATH')) { exit; // Exit if accessed directly } /** * Main plugin class */ class BDFG_Product_Analytics { /** * Plugin version * * @var string */ private $version = '2.1.0'; /** * The single instance of the class * * @var BDFG_Product_Analytics */ protected static $_instance = null; /** * Main analytics table name * * @var string */ private $table_name; /** * Conversions tracking table name * * @var string */ private $conversions_table_name; /** * Plugin directory path * * @var string */ private $plugin_dir; /** * Plugin directory URL * * @var string */ private $plugin_url; /** * Main instance - ensures only one instance is loaded * * @return BDFG_Product_Analytics */ public static function instance() { if (is_null(self::$_instance)) { self::$_instance = new self(); } return self::$_instance; } /** * Constructor */ public function __construct() { global $wpdb; // Define plugin constants $this->define_constants(); // Set table names $this->table_name = $wpdb->prefix . 'bdfg_product_analytics'; $this->conversions_table_name = $wpdb->prefix . 'bdfg_product_conversions'; // Set plugin directory path/URL $this->plugin_dir = plugin_dir_path(__FILE__); $this->plugin_url = plugin_dir_url(__FILE__); // Include required files $this->includes(); // Initialize hooks $this->init_hooks(); // Check for WooCommerce add_action('admin_notices', array($this, 'woocommerce_check_notice')); // Initialize the tracker if (class_exists('BDFG_Tracker')) { $tracker = new BDFG_Tracker($this->table_name, $this->conversions_table_name); } // Let other developers know we're loaded do_action('bdfg_product_analytics_loaded'); } /** * Define plugin constants */ private function define_constants() { define('BDFG_PRODUCT_ANALYTICS_VERSION', $this->version); define('BDFG_PRODUCT_ANALYTICS_FILE', __FILE__); define('BDFG_PRODUCT_ANALYTICS_DIR', plugin_dir_path(__FILE__)); define('BDFG_PRODUCT_ANALYTICS_URL', plugin_dir_url(__FILE__)); define('BDFG_PRODUCT_ANALYTICS_ASSETS_URL', plugin_dir_url(__FILE__) . 'assets/'); } /** * Include required core files */ private function includes() { // Core functionality include_once $this->plugin_dir . 'includes/class-bdfg-tracker.php'; include_once $this->plugin_dir . 'includes/class-bdfg-admin.php'; include_once $this->plugin_dir . 'includes/bdfg-core-functions.php'; // Admin-specific functionality if (is_admin()) { include_once $this->plugin_dir . 'includes/admin/class-bdfg-dashboard.php'; include_once $this->plugin_dir . 'includes/admin/class-bdfg-reports.php'; include_once $this->plugin_dir . 'includes/admin/class-bdfg-settings.php'; } } /** * Initialize hooks */ private function init_hooks() { // Plugin activation/deactivation hooks register_activation_hook(__FILE__, array($this, 'install')); register_deactivation_hook(__FILE__, array($this, 'deactivate')); // Check if we need to update database add_action('plugins_loaded', array($this, 'check_version')); // Load textdomain for translations add_action('plugins_loaded', array($this, 'load_textdomain')); // Schedule cleanup events add_action('bdfg_daily_cleanup', array($this, 'cleanup_old_data')); // Add links to plugin page add_filter('plugin_action_links_' . plugin_basename(__FILE__), array($this, 'plugin_action_links')); } /** * Load plugin textdomain */ public function load_textdomain() { load_plugin_textdomain('bdfg-product-analytics', false, dirname(plugin_basename(__FILE__)) . '/languages'); } /** * Plugin installation */ public function install() { // Check if WooCommerce is active if (!$this->is_woocommerce_active()) { deactivate_plugins(plugin_basename(__FILE__)); wp_die(__('BDFG Product Analytics requires WooCommerce to be installed and active. Please activate WooCommerce and try again.', 'bdfg-product-analytics')); return; } global $wpdb; $charset_collate = $wpdb->get_charset_collate(); // Create our main analytics table $sql = "CREATE TABLE IF NOT EXISTS {$this->table_name} ( id bigint(20) NOT NULL AUTO_INCREMENT, product_id bigint(20) NOT NULL, impressions bigint(20) NOT NULL DEFAULT 0, clicks bigint(20) NOT NULL DEFAULT 0, last_updated datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY product_id (product_id), KEY impressions (impressions), KEY clicks (clicks) ) $charset_collate;"; // Create conversions tracking table $sql2 = "CREATE TABLE IF NOT EXISTS {$this->conversions_table_name} ( id bigint(20) NOT NULL AUTO_INCREMENT, product_id bigint(20) NOT NULL, order_id bigint(20) NOT NULL, conversion_value decimal(10,2) NOT NULL, conversion_date datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY product_id (product_id), KEY order_id (order_id), KEY conversion_date (conversion_date) ) $charset_collate;"; require_once(ABSPATH . 'wp-admin/includes/upgrade.php'); dbDelta($sql); dbDelta($sql2); // Set default options $this->add_default_options(); // Set plugin version in DB update_option('bdfg_product_analytics_version', $this->version); // Schedule cleanup events if (!wp_next_scheduled('bdfg_daily_cleanup')) { wp_schedule_event(time(), 'daily', 'bdfg_daily_cleanup'); } // Trigger action for other extensions to hook into do_action('bdfg_product_analytics_installed'); } /** * Add default options */ private function add_default_options() { // Default settings add_option('bdfg_tracking_enabled', 1); add_option('bdfg_data_retention_days', 365); add_option('bdfg_dashboard_widgets', 1); add_option('bdfg_tracking_location', 'all'); } /** * Plugin deactivation */ public function deactivate() { // Clear scheduled tasks wp_clear_scheduled_hook('bdfg_daily_cleanup'); // Let other extensions know we're deactivating do_action('bdfg_product_analytics_deactivated'); } /** * Check if plugin version has changed and needs updates */ public function check_version() { if (get_option('bdfg_product_analytics_version') !== $this->version) { $this->install(); } } /** * Cleanup old analytics data */ public function cleanup_old_data() { global $wpdb; // Get retention period $retention_days = absint(get_option('bdfg_data_retention_days', 365)); // Only remove data if retention is set (0 = keep forever) if ($retention_days > 0) { // Remove old conversion data $wpdb->query($wpdb->prepare( "DELETE FROM {$this->conversions_table_name} WHERE conversion_date < DATE_SUB(NOW(), INTERVAL %d DAY)", $retention_days )); // Log cleanup operation bdfg_log('Cleaned up old analytics data older than ' . $retention_days . ' days'); } } /** * Check if WooCommerce is active * * @return bool */ public function is_woocommerce_active() { $active_plugins = (array) get_option('active_plugins', array()); if (is_multisite()) { $active_plugins = array_merge($active_plugins, get_site_option('active_sitewide_plugins', array())); } return in_array('woocommerce/woocommerce.php', $active_plugins) || array_key_exists('woocommerce/woocommerce.php', $active_plugins); } /** * WooCommerce not installed notice */ public function woocommerce_check_notice() { if (!$this->is_woocommerce_active()) { ?> <div class="error"> <p><?php _e('BDFG Product Analytics requires WooCommerce to be installed and active. Please activate WooCommerce to continue using BDFG Product Analytics.', 'bdfg-product-analytics'); ?></p> </div> <?php } } /** * Add action links to the plugins page * * @param array $links Plugin action links * @return array Modified action links */ public function plugin_action_links($links) { $plugin_links = array( '<a href="' . admin_url('admin.php?page=bdfg-product-analytics') . '">' . __('Dashboard', 'bdfg-product-analytics') . '</a>', '<a href="' . admin_url('admin.php?page=bdfg-product-analytics-settings') . '">' . __('Settings', 'bdfg-product-analytics') . '</a>', ); // Documentation link $plugin_links[] = '<a href="https://beiduofengou.net/docs/product-analytics/" target="_blank">' . __('Docs', 'bdfg-product-analytics') . '</a>'; return array_merge($plugin_links, $links); } } /** * Initialize the main plugin * * @return BDFG_Product_Analytics */ function BDFG_Product_Analytics() { return BDFG_Product_Analytics::instance(); } // Global for backwards compatibility $GLOBALS['bdfg_product_analytics'] = BDFG_Product_Analytics(); /** * Helper function to get product stats * * @param int $product_id Product ID * @return object Stats object */ if (!function_exists('bdfg_get_product_stats')) { function bdfg_get_product_stats($product_id) { global $wpdb; $table_name = $wpdb->prefix . 'bdfg_product_analytics'; $conversions_table_name = $wpdb->prefix . 'bdfg_product_conversions'; $stats = $wpdb->get_row($wpdb->prepare( "SELECT pa.impressions, pa.clicks, COUNT(conv.id) as conversions, SUM(conv.conversion_value) as revenue FROM {$table_name} as pa LEFT JOIN {$conversions_table_name} as conv ON pa.product_id = conv.product_id WHERE pa.product_id = %d GROUP BY pa.product_id", $product_id )); if (!$stats) { return (object) array( 'impressions' => 0, 'clicks' => 0, 'ctr' => 0, 'conversions' => 0, 'revenue' => 0 ); } $stats->ctr = ($stats->impressions > 0) ? round(($stats->clicks / $stats->impressions) * 100, 2) : 0; return $stats; } }
includes/class-bdfg-tracker.php
<?php /** * BDFG Product Analytics - Tracker Class * * Handles tracking impressions, clicks, and conversions * * @package BDFG_Product_Analytics * @since 2.1.0 */ // Exit if accessed directly if (!defined('ABSPATH')) { exit; } /** * BDFG_Tracker class */ class BDFG_Tracker { /** * Analytics table name * * @var string */ private $table_name; /** * Conversions table name * * @var string */ private $conversions_table_name; /** * Constructor * * @param string $table_name Analytics table name * @param string $conversions_table_name Conversions table name */ public function __construct($table_name, $conversions_table_name) { $this->table_name = $table_name; $this->conversions_table_name = $conversions_table_name; // Only initialize tracking if enabled in settings if (get_option('bdfg_tracking_enabled', 1)) { $this->init(); } } /** * Initialize tracking */ public function init() { // AJAX handlers add_action('wp_ajax_bdfg_track_impression', array($this, 'track_impression')); add_action('wp_ajax_nopriv_bdfg_track_impression', array($this, 'track_impression')); add_action('wp_ajax_bdfg_track_click', array($this, 'track_click')); add_action('wp_ajax_nopriv_bdfg_track_click', array($this, 'track_click')); // WooCommerce hooks $tracking_location = get_option('bdfg_tracking_location', 'all'); if ($tracking_location === 'all' || $tracking_location === 'shop') { add_action('woocommerce_before_shop_loop_item', array($this, 'track_product_impression'), 9); } add_action('woocommerce_after_shop_loop_item', array($this, 'add_click_tracking'), 20); // Track conversions on order completion add_action('woocommerce_order_status_completed', array($this, 'track_conversion')); // Frontend scripts add_action('wp_enqueue_scripts', array($this, 'enqueue_frontend_scripts')); } /** * Enqueue frontend tracking scripts */ public function enqueue_frontend_scripts() { // Only load scripts on product-related pages if (!is_product() && !is_shop() && !is_product_category() && !is_product_tag()) { return; } // Core tracking script wp_enqueue_script( 'bdfg-product-analytics-frontend', BDFG_PRODUCT_ANALYTICS_ASSETS_URL . 'js/frontend.js', array('jquery'), BDFG_PRODUCT_ANALYTICS_VERSION, true ); // Pass data to script wp_localize_script( 'bdfg-product-analytics-frontend', 'bdfgAnalytics', array( 'ajax_url' => admin_url('admin-ajax.php'), 'nonce' => wp_create_nonce('bdfg_product_analytics_nonce'), 'delay' => apply_filters('bdfg_impression_delay', 1000), 'debug' => defined('WP_DEBUG') && WP_DEBUG ? true : false ) ); } /** * Track product impression in shop loop */ public function track_product_impression() { global $product; if (!$product) { return; } // Add data attribute for impression tracking via JS echo '<div class="bdfg-product-impression" data-product-id="' . esc_attr($product->get_id()) . '"></div>'; } /** * Add click tracking to products */ public function add_click_tracking() { global $product; if (!$product) { return; } // Add data attribute for click tracking echo "<script> (function($) { $(document).ready(function() { $('a[href*=\"" . esc_js(get_permalink($product->get_id())) . "\"]').attr('data-bdfg-product-id', " . esc_js($product->get_id()) . "); }); })(jQuery); </script>"; } /** * AJAX handler for impression tracking */ public function track_impression() { check_ajax_referer('bdfg_product_analytics_nonce', 'nonce'); $product_id = isset($_POST['product_id']) ? absint($_POST['product_id']) : 0; if ($product_id > 0) { $this->update_product_stats($product_id, 'impressions'); wp_send_json_success(); } wp_send_json_error('Invalid product ID'); } /** * AJAX handler for click tracking */ public function track_click() { check_ajax_referer('bdfg_product_analytics_nonce', 'nonce'); $product_id = isset($_POST['product_id']) ? absint($_POST['product_id']) : 0; if ($product_id > 0) { $this->update_product_stats($product_id, 'clicks'); wp_send_json_success(); } wp_send_json_error('Invalid product ID'); } /** * Track conversion on completed order * * @param int $order_id Order ID */ public function track_conversion($order_id) { $order = wc_get_order($order_id); if (!$order) { return; } global $wpdb; // Loop through each item in the order foreach ($order->get_items() as $item) { $product_id = $item->get_product_id(); $total = $item->get_total(); // Track this conversion $wpdb->insert( $this->conversions_table_name, array( 'product_id' => $product_id, 'order_id' => $order_id, 'conversion_value' => $total, 'conversion_date' => current_time('mysql', true) ) ); do_action('bdfg_product_conversion_tracked', $product_id, $order_id, $total); } } /** * Update product statistics * * @param int $product_id Product ID * @param string $type Stats type (impressions|clicks) * @return boolean Success or failure */ private function update_product_stats($product_id, $type) { global $wpdb; // Validate product exists $product = wc_get_product($product_id); if (!$product) { return false; } // Check if record exists $exists = $wpdb->get_var($wpdb->prepare( "SELECT id FROM {$this->table_name} WHERE product_id = %d", $product_id )); $result = false; if ($exists) { // Update existing record $result = $wpdb->query($wpdb->prepare( "UPDATE {$this->table_name} SET {$type} = {$type} + 1, last_updated = %s WHERE product_id = %d", current_time('mysql', true), $product_id )); } else { // Create new record $data = array( 'product_id' => $product_id, 'impressions' => ($type === 'impressions') ? 1 : 0, 'clicks' => ($type === 'clicks') ? 1 : 0, 'last_updated' => current_time('mysql', true) ); $result = $wpdb->insert($this->table_name, $data); } if ($result !== false) { do_action('bdfg_product_' . $type . '_tracked', $product_id); } return ($result !== false); } }
includes/bdfg-core-functions.php
相关文章: WordPress优惠券提醒插件系统
<?php /** * BDFG Product Analytics - Core Functions * * Core functions available globally * * @package BDFG_Product_Analytics * @since 2.1.0 */ // Exit if accessed directly if (!defined('ABSPATH')) { exit; } /** * Get product analytics stats * * @param int $product_id Product ID * @param string $time_range Time range (all, 7d, 30d, 90d, year) * @return object Stats object */ function bdfg_get_product_stats($product_id, $time_range = 'all') { global $wpdb; $table_name = $wpdb->prefix . 'bdfg_product_analytics'; $conversions_table_name = $wpdb->prefix . 'bdfg_product_conversions'; // Generate date condition $date_condition = ''; switch ($time_range) { case '7d': $date_condition = " AND conversion_date >= DATE_SUB(NOW(), INTERVAL 7 DAY)"; break; case '30d': $date_condition = " AND conversion_date >= DATE_SUB(NOW(), INTERVAL 30 DAY)"; break; case '90d': $date_condition = " AND conversion_date >= DATE_SUB(NOW(), INTERVAL 90 DAY)"; break; case 'year': $date_condition = " AND conversion_date >= DATE_SUB(NOW(), INTERVAL 1 YEAR)"; break; case 'all': default: $date_condition = ""; break; } $stats = $wpdb->get_row($wpdb->prepare( "SELECT pa.impressions, pa.clicks, COUNT(conv.id) as conversions, SUM(conv.conversion_value) as revenue FROM {$table_name} as pa LEFT JOIN {$conversions_table_name} as conv ON pa.product_id = conv.product_id {$date_condition} WHERE pa.product_id = %d GROUP BY pa.product_id", $product_id )); if (!$stats) { return (object) array( 'impressions' => 0, 'clicks' => 0, 'ctr' => 0, 'conversions' => 0, 'revenue' => 0 ); } // Calculate CTR $stats->ctr = ($stats->impressions > 0) ? round(($stats->clicks / $stats->impressions) * 100, 2) : 0; // Ensure revenue is not null $stats->revenue = $stats->revenue ? $stats->revenue : 0; return $stats; } /** * Get top performing products * * @param string $metric Metric to sort by (ctr, impressions, clicks, conversions, revenue) * @param string $time_range Time range (all, 7d, 30d, 90d, year) * @param int $limit Number of products to return * @return array Array of product data */ function bdfg_get_top_products($metric = 'ctr', $time_range = '30d', $limit = 10) { global $wpdb; $table_name = $wpdb->prefix . 'bdfg_product_analytics'; $conversions_table_name = $wpdb->prefix . 'bdfg_product_conversions'; // Generate date condition $date_condition = ''; switch ($time_range) { case '7d': $date_condition = " AND conv.conversion_date >= DATE_SUB(NOW(), INTERVAL 7 DAY)"; break; case '30d': $date_condition = " AND conv.conversion_date >= DATE_SUB(NOW(), INTERVAL 30 DAY)"; break; case '90d': $date_condition = " AND conv.conversion_date >= DATE_SUB(NOW(), INTERVAL 90 DAY)"; break; case 'year': $date_condition = " AND conv.conversion_date >= DATE_SUB(NOW(), INTERVAL 1 YEAR)"; break; case 'all': default: $date_condition = ""; break; } // Set minimum threshold for meaningful data $threshold = apply_filters('bdfg_analytics_threshold', 5); // Validate and sanitize metric for sorting $valid_metrics = array('ctr', 'impressions', 'clicks', 'conversions', 'revenue'); if (!in_array($metric, $valid_metrics)) { $metric = 'ctr'; // Default fallback } // Define the ORDER BY clause based on metric switch ($metric) { case 'ctr': $order_by = "ROUND((pa.clicks / NULLIF(pa.impressions, 0)) * 100, 2) DESC"; break; case 'impressions': $order_by = "pa.impressions DESC"; break; case 'clicks': $order_by = "pa.clicks DESC"; break; case 'conversions': $order_by = "conversions DESC"; break; case 'revenue': $order_by = "revenue DESC"; break; default: $order_by = "ROUND((pa.clicks / NULLIF(pa.impressions, 0)) * 100, 2) DESC"; } // Query for top products $products = $wpdb->get_results( "SELECT pa.product_id, p.post_title as product_name, pa.impressions, pa.clicks, ROUND((pa.clicks / NULLIF(pa.impressions, 0)) * 100, 2) as ctr, COUNT(conv.id) as conversions, SUM(conv.conversion_value) as revenue, MAX(pm.meta_value) as product_image FROM {$table_name} as pa JOIN {$wpdb->posts} as p ON pa.product_id = p.ID LEFT JOIN {$conversions_table_name} as conv ON pa.product_id = conv.product_id {$date_condition} LEFT JOIN {$wpdb->postmeta} as pm ON pa.product_id = pm.post_id AND pm.meta_key = '_thumbnail_id' WHERE p.post_status = 'publish' AND pa.impressions >= {$threshold} GROUP BY pa.product_id ORDER BY {$order_by} LIMIT " . absint($limit) ); // Format the results $results = array(); foreach ($products as $product) { $product_obj = wc_get_product($product->product_id); if (!$product_obj) { continue; } $thumbnail = $product->product_image ? wp_get_attachment_image_url($product->product_image, 'thumbnail') : wc_placeholder_img_src(); $results[] = array( 'id' => $product->product_id, 'name' => $product->product_name, 'permalink' => get_permalink($product->product_id), 'thumbnail' => $thumbnail, 'price' => $product_obj->get_price(), 'formatted_price' => $product_obj->get_price_html(), 'impressions' => (int) $product->impressions, 'clicks' => (int) $product->clicks, 'ctr' => (float) $product->ctr, 'conversions' => (int) $product->conversions, 'revenue' => (float) $product->revenue ); } return $results; } /** * Get analytics summary data * * @param string $time_range Time range (all, 7d, 30d, 90d, year) * @return object Summary data object */ function bdfg_get_analytics_summary($time_range = '30d') { global $wpdb; $table_name = $wpdb->prefix . 'bdfg_product_analytics'; $conversions_table_name = $wpdb->prefix . 'bdfg_product_conversions'; // Generate date condition for conversions $date_condition = ''; switch ($time_range) { case '7d': $date_condition = " WHERE conversion_date >= DATE_SUB(NOW(), INTERVAL 7 DAY)"; break; case '30d': $date_condition = " WHERE conversion_date >= DATE_SUB(NOW(), INTERVAL 30 DAY)"; break; case '90d': $date_condition = " WHERE conversion_date >= DATE_SUB(NOW(), INTERVAL 90 DAY)"; break; case 'year': $date_condition = " WHERE conversion_date >= DATE_SUB(NOW(), INTERVAL 1 YEAR)"; break; case 'all': default: $date_condition = ""; break; } // Get total stats $total_impressions = $wpdb->get_var("SELECT SUM(impressions) FROM {$table_name}"); $total_clicks = $wpdb->get_var("SELECT SUM(clicks) FROM {$table_name}"); $total_ctr = ($total_impressions > 0) ? round(($total_clicks / $total_impressions) * 100, 2) : 0; $total_conversions = $wpdb->get_var("SELECT COUNT(*) FROM {$conversions_table_name}{$date_condition}"); $total_revenue = $wpdb->get_var("SELECT SUM(conversion_value) FROM {$conversions_table_name}{$date_condition}"); // Get top performing product by CTR $top_ctr_product = $wpdb->get_row( "SELECT pa.product_id, p.post_title as name, ROUND((pa.clicks / NULLIF(pa.impressions, 0)) * 100, 2) as ctr FROM {$table_name} as pa JOIN {$wpdb->posts} as p ON pa.product_id = p.ID WHERE pa.impressions >= 10 AND p.post_status = 'publish' ORDER BY ctr DESC LIMIT 1" ); // Get top converting product $top_converting_product = $wpdb->get_row( "SELECT pa.product_id, p.post_title as name, COUNT(conv.id) as conversions FROM {$table_name} as pa JOIN {$wpdb->posts} as p ON pa.product_id = p.ID LEFT JOIN {$conversions_table_name} as conv ON pa.product_id = conv.product_id {$date_condition} WHERE p.post_status = 'publish' GROUP BY pa.product_id ORDER BY conversions DESC LIMIT 1" ); // Compile summary data $summary = (object) array( 'total_impressions' => (int) $total_impressions, 'total_clicks' => (int) $total_clicks, 'total_ctr' => (float) $total_ctr, 'total_conversions' => (int) $total_conversions, 'total_revenue' => (float) ($total_revenue ? $total_revenue : 0), 'top_ctr_product' => $top_ctr_product ? array( 'id' => $top_ctr_product->product_id, 'name' => $top_ctr_product->name, 'ctr' => $top_ctr_product->ctr ) : null, 'top_converting_product' => $top_converting_product ? array( 'id' => $top_converting_product->product_id, 'name' => $top_converting_product->name, 'conversions' => $top_converting_product->conversions ) : null ); return $summary; } /** * Log debug messages if debugging is enabled * * @param string $message Message to log * @param string $level Log level */ function bdfg_log($message, $level = 'info') { if (defined('WP_DEBUG') && WP_DEBUG === true) { if (is_array($message) || is_object($message)) { $message = print_r($message, true); } $log_entry = '[' . date('Y-m-d H:i:s', current_time('timestamp')) . '] [' . strtoupper($level) . '] ' . $message; if (defined('BDFG_LOG_TO_FILE') && BDFG_LOG_TO_FILE === true) { $log_file = WP_CONTENT_DIR . '/bdfg-analytics-debug.log'; error_log($log_entry . "\n", 3, $log_file); } else { error_log('BDFG Product Analytics: ' . $log_entry); } } } /** * Format large numbers in a readable way * * @param int $number Number to format * @param int $decimals Number of decimal places * @return string Formatted number */ function bdfg_format_number($number, $decimals = 1) { if ($number >= 1000000) { return number_format($number / 1000000, $decimals) . 'M'; } elseif ($number >= 1000) { return number_format($number / 1000, $decimals) . 'K'; } return number_format($number); } /** * Export product analytics data to CSV * * @param string $time_range Time range (all, 7d, 30d, 90d, year) */ function bdfg_export_data_to_csv($time_range = 'all') { if (!current_user_can('manage_options')) { wp_die(__('You do not have sufficient permissions to access this page.', 'bdfg-product-analytics')); } global $wpdb; $table_name = $wpdb->prefix . 'bdfg_product_analytics'; $conversions_table_name = $wpdb->prefix . 'bdfg_product_conversions'; // Generate date condition $date_condition = ''; switch ($time_range) { case '7d': $date_condition = " AND conv.conversion_date >= DATE_SUB(NOW(), INTERVAL 7 DAY)"; break; case '30d': $date_condition = " AND conv.conversion_date >= DATE_SUB(NOW(), INTERVAL 30 DAY)"; break; case '90d': $date_condition = " AND conv.conversion_date >= DATE_SUB(NOW(), INTERVAL 90 DAY)"; break; case 'year': $date_condition = " AND conv.conversion_date >= DATE_SUB(NOW(), INTERVAL 1 YEAR)"; break; case 'all': default: $date_condition = ""; break; } $data = $wpdb->get_results( "SELECT pa.product_id, p.post_title as product_name, p.post_status, pa.impressions, pa.clicks, ROUND((pa.clicks / NULLIF(pa.impressions, 0)) * 100, 2) as ctr, COUNT(conv.id) as conversions, SUM(conv.conversion_value) as revenue FROM {$table_name} as pa JOIN {$wpdb->posts} as p ON pa.product_id = p.ID LEFT JOIN {$conversions_table_name} as conv ON pa.product_id = conv.product_id {$date_condition} GROUP BY pa.product_id ORDER BY ctr DESC" ); // Set headers for CSV download header('Content-Type: text/csv; charset=utf-8'); header('Content-Disposition: attachment; filename=bdfg_product_analytics_' . date('Y-m-d_H-i') . '.csv'); // Create output stream $output = fopen('php://output', 'w'); // Add UTF-8 BOM for proper encoding in Excel fprintf($output, chr(0xEF).chr(0xBB).chr(0xBF)); // Add CSV header row fputcsv($output, array( __('Product ID', 'bdfg-product-analytics'), __('Product Name', 'bdfg-product-analytics'), __('Status', 'bdfg-product-analytics'), __('Impressions', 'bdfg-product-analytics'), __('Clicks', 'bdfg-product-analytics'), __('CTR (%)', 'bdfg-product-analytics'), __('Conversions', 'bdfg-product-analytics'), __('Revenue', 'bdfg-product-analytics') )); // Add data rows foreach ($data as $row) { fputcsv($output, array( $row->product_id, $row->product_name, $row->post_status, $row->impressions, $row->clicks, $row->ctr, $row->conversions, $row->revenue )); } fclose($output); exit; }
includes/admin/class-bdfg-dashboard.php
<?php /** * BDFG Product Analytics - Dashboard Class * * Handles dashboard page display * * @package BDFG_Product_Analytics * @since 2.1.0 */ // Exit if accessed directly if (!defined('ABSPATH')) { exit; } /** * BDFG_Dashboard class */ class BDFG_Dashboard { /** * Constructor */ public function __construct() { // Nothing to construct here, we'll initialize as needed } /** * Output the dashboard page */ public function output() { $time_range = isset($_GET['range']) ? sanitize_text_field($_GET['range']) : '30d'; $summary = bdfg_get_analytics_summary($time_range); $top_products = bdfg_get_top_products('ctr', $time_range, 10); // Get date for display $current_date = '2025-03-06'; // Using provided date ?> <div class="wrap bdfg-analytics-wrap"> <h1><?php _e('BDFG Product Analytics Dashboard', 'bdfg-product-analytics'); ?></h1> <div class="bdfg-time-range"> <form method="get"> <input type="hidden" name="page" value="bdfg-product-analytics"> <select name="range" onchange="this.form.submit()"> <option value="7d" <?php selected($time_range, '7d'); ?>><?php _e('Last 7 Days', 'bdfg-product-analytics'); ?></option> <option value="30d" <?php selected($time_range, '30d'); ?>><?php _e('Last 30 Days', 'bdfg-product-analytics'); ?></option> <option value="90d" <?php selected($time_range, '90d'); ?>><?php _e('Last 90 Days', 'bdfg-product-analytics'); ?></option> <option value="year" <?php selected($time_range, 'year'); ?>><?php _e('Last Year', 'bdfg-product-analytics'); ?></option> <option value="all" <?php selected($time_range, 'all'); ?>><?php _e('All Time', 'bdfg-product-analytics'); ?></option> </select> </form> <div class="bdfg-export-button"> <a href="<?php echo wp_nonce_url(admin_url('admin-ajax.php?action=bdfg_export_analytics&range=' . $time_range), 'bdfg_export_analytics'); ?>" class="button"> <span class="dashicons dashicons-download" style="margin-top: 3px;"></span> <?php _e('Export to CSV', 'bdfg-product-analytics'); ?> </a> </div> </div> <div class="bdfg-summary-cards"> <div class="bdfg-card"> <div class="bdfg-card-content"> <h3><?php _e('Impressions', 'bdfg-product-analytics'); ?></h3> <div class="bdfg-card-value"><?php echo number_format($summary->total_impressions); ?></div> <div class="bdfg-card-description"><?php _e('Total number of times products were viewed', 'bdfg-product-analytics'); ?></div> </div> </div> <div class="bdfg-card"> <div class="bdfg-card-content"> <h3><?php _e('Clicks', 'bdfg-product-analytics'); ?></h3> <div class="bdfg-card-value"><?php echo number_format($summary->total_clicks); ?></div> <div class="bdfg-card-description"><?php _e('Total number of clicks on products', 'bdfg-product-analytics'); ?></div> </div> </div> <div class="bdfg-card"> <div class="bdfg-card-content"> <h3><?php _e('CTR', 'bdfg-product-analytics'); ?></h3> <div class="bdfg-card-value"><?php echo $summary->total_ctr; ?>%</div> <div class="bdfg-card-description"><?php _e('Average click-through rate', 'bdfg-product-analytics'); ?></div> </div> </div> <div class="bdfg-card"> <div class="bdfg-card-content"> <h3><?php _e('Conversions', 'bdfg-product-analytics'); ?></h3> <div class="bdfg-card-value"><?php echo number_format($summary->total_conversions); ?></div> <div class="bdfg-card-description"><?php _e('Total number of product purchases', 'bdfg-product-analytics'); ?></div> </div> </div> <div class="bdfg-card"> <div class="bdfg-card-content"> <h3><?php _e('Revenue', 'bdfg-product-analytics'); ?></h3> <div class="bdfg-card-value"><?php echo wc_price($summary->total_revenue); ?></div> <div class="bdfg-card-description"><?php _e('Total revenue from product sales', 'bdfg-product-analytics'); ?></div> </div> </div> </div> <div class="bdfg-charts-container"> <div class="bdfg-chart-card"> <h2><?php _e('Top Performing Products by CTR', 'bdfg-product-analytics'); ?></h2> <div class="bdfg-chart-container"> <canvas id="bdfg-ctr-chart"></canvas> </div> </div> <div class="bdfg-chart-card"> <h2><?php _e('Impressions vs Clicks', 'bdfg-product-analytics'); ?></h2> <div class="bdfg-chart-container"> <canvas id="bdfg-clicks-chart"></canvas> </div> </div> </div> <div class="bdfg-table-container"> <h2><?php _e('Top Performing Products', 'bdfg-product-analytics'); ?></h2> <table class="wp-list-table widefat fixed striped"> <thead> <tr> <th><?php _e('Product', 'bdfg-product-analytics'); ?></th> <th><?php _e('Impressions', 'bdfg-product-analytics'); ?></th> <th><?php _e('Clicks', 'bdfg-product-analytics'); ?></th> <th><?php _e('CTR', 'bdfg-product-analytics'); ?></th> <th><?php _e('Conversions', 'bdfg-product-analytics'); ?></th> <th><?php _e('Revenue', 'bdfg-product-analytics'); ?></th> </tr> </thead> <tbody> <?php foreach ($top_products as $product) : ?> <tr> <td> <a href="<?php echo get_edit_post_link($product['id']); ?>"> <?php echo esc_html($product['name']); ?> </a> </td> <td><?php echo number_format($product['impressions']); ?></td> <td><?php echo number_format($product['clicks']); ?></td> <td><?php echo $product['ctr']; ?>%</td> <td><?php echo number_format($product['conversions']); ?></td> <td><?php echo wc_price($product['revenue']); ?></td> </tr> <?php endforeach; ?> </tbody> </table> <p class="bdfg-view-more"> <a href="<?php echo admin_url('admin.php?page=bdfg-product-analytics-reports'); ?>" class="button"> <?php _e('View Detailed Reports', 'bdfg-product-analytics'); ?> </a> </p> </div> <div class="bdfg-footer"> <p><?php printf(__('BDFG Product Analytics v%s | Data as of %s', 'bdfg-product-analytics'), BDFG_PRODUCT_ANALYTICS_VERSION, $current_date); ?></p> </div> </div> <?php } }
includes/admin/class-bdfg-reports.php
相关文章: WooCommerce 高级产品定价和折扣管理
<?php /** * BDFG Product Analytics - Reports Class * * Handles reports page display and data * * @package BDFG_Product_Analytics * @since 2.1.0 */ // Exit if accessed directly if (!defined('ABSPATH')) { exit; } /** * BDFG_Reports class */ class BDFG_Reports { /** * Constructor */ public function __construct() { // Nothing to construct } /** * Output reports page */ public function output() { $time_range = isset($_GET['range']) ? sanitize_text_field($_GET['range']) : '30d'; $metric = isset($_GET['metric']) ? sanitize_text_field($_GET['metric']) : 'ctr'; $product_id = isset($_GET['product']) ? absint($_GET['product']) : 0; // Current date from provided timestamp $current_date = '2025-03-06'; // Using provided date // Handle single product view if ($product_id) { $this->output_single_product_report($product_id, $time_range); return; } // Get top products by selected metric $products = bdfg_get_top_products($metric, $time_range, 20); ?> <div class="wrap bdfg-analytics-wrap"> <h1><?php _e('BDFG Product Analytics Reports', 'bdfg-product-analytics'); ?></h1> <div class="bdfg-filters"> <form method="get"> <input type="hidden" name="page" value="bdfg-product-analytics-reports"> <div class="bdfg-filter-group"> <label for="range"><?php _e('Time Range:', 'bdfg-product-analytics'); ?></label> <select name="range" id="range"> <option value="7d" <?php selected($time_range, '7d'); ?>><?php _e('Last 7 Days', 'bdfg-product-analytics'); ?></option> <option value="30d" <?php selected($time_range, '30d'); ?>><?php _e('Last 30 Days', 'bdfg-product-analytics'); ?></option> <option value="90d" <?php selected($time_range, '90d'); ?>><?php _e('Last 90 Days', 'bdfg-product-analytics'); ?></option> <option value="year" <?php selected($time_range, 'year'); ?>><?php _e('Last Year', 'bdfg-product-analytics'); ?></option> <option value="all" <?php selected($time_range, 'all'); ?>><?php _e('All Time', 'bdfg-product-analytics'); ?></option> </select> </div> <div class="bdfg-filter-group"> <label for="metric"><?php _e('Sort By:', 'bdfg-product-analytics'); ?></label> <select name="metric" id="metric"> <option value="ctr" <?php selected($metric, 'ctr'); ?>><?php _e('CTR', 'bdfg-product-analytics'); ?></option> <option value="impressions" <?php selected($metric, 'impressions'); ?>><?php _e('Impressions', 'bdfg-product-analytics'); ?></option> <option value="clicks" <?php selected($metric, 'clicks'); ?>><?php _e('Clicks', 'bdfg-product-analytics'); ?></option> <option value="conversions" <?php selected($metric, 'conversions'); ?>><?php _e('Conversions', 'bdfg-product-analytics'); ?></option> <option value="revenue" <?php selected($metric, 'revenue'); ?>><?php _e('Revenue', 'bdfg-product-analytics'); ?></option> </select> </div> <div class="bdfg-filter-group"> <button type="submit" class="button"><?php _e('Apply Filters', 'bdfg-product-analytics'); ?></button> </div> </form> <div class="bdfg-export-button"> <a href="<?php echo wp_nonce_url(admin_url('admin-ajax.php?action=bdfg_export_analytics&range=' . $time_range), 'bdfg_export_analytics'); ?>" class="button"> <span class="dashicons dashicons-download" style="margin-top: 3px;"></span> <?php _e('Export to CSV', 'bdfg-product-analytics'); ?> </a> </div> </div> <div class="bdfg-table-container"> <h2> <?php switch ($metric) { case 'impressions': _e('Products by Impressions', 'bdfg-product-analytics'); break; case 'clicks': _e('Products by Clicks', 'bdfg-product-analytics'); break; case 'conversions': _e('Products by Conversions', 'bdfg-product-analytics'); break; case 'revenue': _e('Products by Revenue', 'bdfg-product-analytics'); break; default: _e('Products by CTR', 'bdfg-product-analytics'); } ?> </h2> <table class="wp-list-table widefat fixed striped"> <thead> <tr> <th><?php _e('Product', 'bdfg-product-analytics'); ?></th> <th><?php _e('Impressions', 'bdfg-product-analytics'); ?></th> <th><?php _e('Clicks', 'bdfg-product-analytics'); ?></th> <th><?php _e('CTR', 'bdfg-product-analytics'); ?></th> <th><?php _e('Conversions', 'bdfg-product-analytics'); ?></th> <th><?php _e('Revenue', 'bdfg-product-analytics'); ?></th> <th><?php _e('Actions', 'bdfg-product-analytics'); ?></th> </tr> </thead> <tbody> <?php if (empty($products)) : ?> <tr> <td colspan="7"><?php _e('No product data found for the selected filters.', 'bdfg-product-analytics'); ?></td> </tr> <?php else : ?> <?php foreach ($products as $product) : ?> <tr> <td> <a href="<?php echo get_edit_post_link($product['id']); ?>"> <?php echo esc_html($product['name']); ?> </a> </td> <td><?php echo number_format($product['impressions']); ?></td> <td><?php echo number_format($product['clicks']); ?></td> <td><?php echo $product['ctr']; ?>%</td> <td><?php echo number_format($product['conversions']); ?></td> <td><?php echo wc_price($product['revenue']); ?></td> <td> <a href="<?php echo admin_url('admin.php?page=bdfg-product-analytics-reports&product=' . $product['id'] . '&range=' . $time_range); ?>" class="button button-small"> <?php _e('Details', 'bdfg-product-analytics'); ?> </a> </td> </tr> <?php endforeach; ?> <?php endif; ?> </tbody> </table> </div> <div class="bdfg-footer"> <p><?php printf(__('BDFG Product Analytics v%s | Data as of %s', 'bdfg-product-analytics'), BDFG_PRODUCT_ANALYTICS_VERSION, date('Y-m-d H:i:s', current_time('timestamp'))); ?></p> </div> </div> <?php } /** * Output single product report * * @param int $product_id Product ID * @param string $time_range Time range (all, 7d, 30d, 90d, year) */ private function output_single_product_report($product_id, $time_range) { $product = wc_get_product($product_id); if (!$product) { wp_die(__('Product not found.', 'bdfg-product-analytics')); } $stats = bdfg_get_product_stats($product_id, $time_range); $conversion_rate = ($stats->clicks > 0) ? round(($stats->conversions / $stats->clicks) * 100, 2) : 0; // Get conversion data over time for chart global $wpdb; $conversions_table_name = $wpdb->prefix . 'bdfg_product_conversions'; $date_range_sql = ''; switch ($time_range) { case '7d': $date_range_sql = "AND conversion_date >= DATE_SUB(NOW(), INTERVAL 7 DAY)"; break; case '30d': $date_range_sql = "AND conversion_date >= DATE_SUB(NOW(), INTERVAL 30 DAY)"; break; case '90d': $date_range_sql = "AND conversion_date >= DATE_SUB(NOW(), INTERVAL 90 DAY)"; break; case 'year': $date_range_sql = "AND conversion_date >= DATE_SUB(NOW(), INTERVAL 1 YEAR)"; break; } $conversion_data = $wpdb->get_results($wpdb->prepare( "SELECT DATE(conversion_date) as date, COUNT(*) as conversions, SUM(conversion_value) as revenue FROM {$conversions_table_name} WHERE product_id = %d $date_range_sql GROUP BY DATE(conversion_date) ORDER BY date ASC", $product_id )); // Format the data for JS chart $labels = array(); $conversions_data = array(); $revenue_data = array(); foreach ($conversion_data as $data) { $labels[] = $data->date; $conversions_data[] = $data->conversions; $revenue_data[] = $data->revenue; } $chart_data = array( 'labels' => $labels, 'conversions' => $conversions_data, 'revenue' => $revenue_data ); // Current date from provided timestamp $current_date = '2025-03-06 10:03:13'; // Using provided date and time ?> <div class="wrap bdfg-analytics-wrap"> <h1> <?php printf(__('Analytics for: %s', 'bdfg-product-analytics'), $product->get_name()); ?> <a href="<?php echo admin_url('admin.php?page=bdfg-product-analytics-reports&range=' . $time_range); ?>" class="page-title-action"><?php _e('Back to Reports', 'bdfg-product-analytics'); ?></a> </h1> <div class="bdfg-time-range"> <form method="get"> <input type="hidden" name="page" value="bdfg-product-analytics-reports"> <input type="hidden" name="product" value="<?php echo $product_id; ?>"> <select name="range" onchange="this.form.submit()"> <option value="7d" <?php selected($time_range, '7d'); ?>><?php _e('Last 7 Days', 'bdfg-product-analytics'); ?></option> <option value="30d" <?php selected($time_range, '30d'); ?>><?php _e('Last 30 Days', 'bdfg-product-analytics'); ?></option> <option value="90d" <?php selected($time_range, '90d'); ?>><?php _e('Last 90 Days', 'bdfg-product-analytics'); ?></option> <option value="year" <?php selected($time_range, 'year'); ?>><?php _e('Last Year', 'bdfg-product-analytics'); ?></option> <option value="all" <?php selected($time_range, 'all'); ?>><?php _e('All Time', 'bdfg-product-analytics'); ?></option> </select> </form> </div> <div class="bdfg-product-header"> <?php if ($product->get_image_id()) : ?> <div class="bdfg-product-image"> <?php echo $product->get_image('thumbnail'); ?> </div> <?php endif; ?> <div class="bdfg-product-info"> <h2><?php echo $product->get_name(); ?></h2> <p class="bdfg-product-sku"><?php _e('SKU:', 'bdfg-product-analytics'); ?> <?php echo $product->get_sku() ? $product->get_sku() : __('N/A', 'bdfg-product-analytics'); ?></p> <p class="bdfg-product-price"><?php _e('Price:', 'bdfg-product-analytics'); ?> <?php echo $product->get_price_html(); ?></p> <p> <a href="<?php echo get_permalink($product_id); ?>" target="_blank" class="button button-secondary"><?php _e('View Product', 'bdfg-product-analytics'); ?></a> <a href="<?php echo get_edit_post_link($product_id); ?>" class="button button-secondary"><?php _e('Edit Product', 'bdfg-product-analytics'); ?></a> </p> </div> </div> <div class="bdfg-summary-cards"> <div class="bdfg-card"> <div class="bdfg-card-content"> <h3><?php _e('Impressions', 'bdfg-product-analytics'); ?></h3> <div class="bdfg-card-value"><?php echo number_format($stats->impressions); ?></div> </div> </div> <div class="bdfg-card"> <div class="bdfg-card-content"> <h3><?php _e('Clicks', 'bdfg-product-analytics'); ?></h3> <div class="bdfg-card-value"><?php echo number_format($stats->clicks); ?></div> </div> </div> <div class="bdfg-card"> <div class="bdfg-card-content"> <h3><?php _e('CTR', 'bdfg-product-analytics'); ?></h3> <div class="bdfg-card-value"><?php echo $stats->ctr; ?>%</div> </div> </div> <div class="bdfg-card"> <div class="bdfg-card-content"> <h3><?php _e('Conversions', 'bdfg-product-analytics'); ?></h3> <div class="bdfg-card-value"><?php echo number_format($stats->conversions); ?></div> </div> </div> <div class="bdfg-card"> <div class="bdfg-card-content"> <h3><?php _e('Revenue', 'bdfg-product-analytics'); ?></h3> <div class="bdfg-card-value"><?php echo wc_price($stats->revenue); ?></div> </div> </div> <div class="bdfg-card"> <div class="bdfg-card-content"> <h3><?php _e('Conversion Rate', 'bdfg-product-analytics'); ?></h3> <div class="bdfg-card-value"><?php echo $conversion_rate; ?>%</div> <div class="bdfg-card-description"><?php _e('Conversions / Clicks', 'bdfg-product-analytics'); ?></div> </div> </div> </div> <div class="bdfg-charts-container"> <div class="bdfg-chart-card"> <h2><?php _e('Conversions Over Time', 'bdfg-product-analytics'); ?></h2> <div class="bdfg-chart-container"> <canvas id="bdfg-conversions-chart"></canvas> </div> </div> <div class="bdfg-chart-card"> <h2><?php _e('Revenue Over Time', 'bdfg-product-analytics'); ?></h2> <div class="bdfg-chart-container"> <canvas id="bdfg-revenue-chart"></canvas> </div> </div> </div> <div class="bdfg-recommendations"> <h2><?php _e('BDFG Analytics Insights', 'bdfg-product-analytics'); ?></h2> <div class="bdfg-recommendation-card"> <?php if ($stats->ctr < 2) : ?> <h3><?php _e('Low CTR Alert', 'bdfg-product-analytics'); ?></h3> <p><?php _e('This product has a lower CTR than average. Consider updating the product image or improving its visibility in your store.', 'bdfg-product-analytics'); ?></p> <?php elseif ($stats->clicks > 0 && $conversion_rate < 1) : ?> <h3><?php _e('Low Conversion Rate', 'bdfg-product-analytics'); ?></h3> <p><?php _e('This product gets clicks but few conversions. Consider reviewing the product description, images, and pricing strategy.', 'bdfg-product-analytics'); ?></p> <?php elseif ($stats->conversions > 0) : ?> <h3><?php _e('Strong Performance', 'bdfg-product-analytics'); ?></h3> <p><?php _e('This product is performing well with good conversions. Consider increasing its visibility or running a promotion to maximize sales.', 'bdfg-product-analytics'); ?></p> <?php else : ?> <h3><?php _e('Insufficient Data', 'bdfg-product-analytics'); ?></h3> <p><?php _e('Not enough data is available to provide meaningful insights for this product yet.', 'bdfg-product-analytics'); ?></p> <?php endif; ?> </div> </div> <script type="text/javascript"> jQuery(document).ready(function($) { var ctx1 = document.getElementById('bdfg-conversions-chart').getContext('2d'); var ctx2 = document.getElementById('bdfg-revenue-chart').getContext('2d'); var labels = <?php echo json_encode($chart_data['labels']); ?>; var conversionsData = <?php echo json_encode($chart_data['conversions']); ?>; var revenueData = <?php echo json_encode($chart_data['revenue']); ?>; // Conversions chart new Chart(ctx1, { type: 'bar', data: { labels: labels, datasets: [{ label: '<?php _e('Conversions', 'bdfg-product-analytics'); ?>', data: conversionsData, backgroundColor: 'rgba(54, 162, 235, 0.5)', borderColor: 'rgba(54, 162, 235, 1)', borderWidth: 1 }] }, options: { scales: { y: { beginAtZero: true, ticks: { precision: 0 } } } } }); // Revenue chart new Chart(ctx2, { type: 'line', data: { labels: labels, datasets: [{ label: '<?php _e('Revenue', 'bdfg-product-analytics'); ?>', data: revenueData, backgroundColor: 'rgba(75, 192, 192, 0.2)', borderColor: 'rgba(75, 192, 192, 1)', borderWidth: 2, tension: 0.2 }] }, options: { scales: { y: { beginAtZero: true } } } }); }); </script> <div class="bdfg-footer"> <p><?php printf(__('BDFG Product Analytics v%s | Data as of %s | Generated by %s', 'bdfg-product-analytics'), BDFG_PRODUCT_ANALYTICS_VERSION, '2025-03-06 10:18:50', 'beiduofengou'); ?></p> </div> </div> <?php } }
includes/admin/class-bdfg-settings.php
<?php /** * BDFG Product Analytics - Settings Class * * Handles settings page display and functionality * * @package BDFG_Product_Analytics * @since 2.1.0 */ // Exit if accessed directly if (!defined('ABSPATH')) { exit; } /** * BDFG_Settings class */ class BDFG_Settings { /** * Constructor */ public function __construct() { // Register settings add_action('admin_init', array($this, 'register_settings')); } /** * Register plugin settings */ public function register_settings() { register_setting('bdfg_product_analytics_settings', 'bdfg_tracking_enabled'); register_setting('bdfg_product_analytics_settings', 'bdfg_data_retention_days', array( 'sanitize_callback' => 'absint' )); register_setting('bdfg_product_analytics_settings', 'bdfg_dashboard_widgets'); register_setting('bdfg_product_analytics_settings', 'bdfg_tracking_location'); } /** * Output settings page */ public function output() { if (isset($_POST['bdfg_save_settings']) && check_admin_referer('bdfg_settings_save', 'bdfg_settings_nonce')) { // Handle settings save update_option('bdfg_tracking_enabled', isset($_POST['bdfg_tracking_enabled']) ? 1 : 0); update_option('bdfg_data_retention_days', absint($_POST['bdfg_data_retention_days'])); update_option('bdfg_dashboard_widgets', isset($_POST['bdfg_dashboard_widgets']) ? 1 : 0); update_option('bdfg_tracking_location', sanitize_text_field($_POST['bdfg_tracking_location'])); // Display success message echo '<div class="notice notice-success is-dismissible"><p>' . __('Settings saved successfully.', 'bdfg-product-analytics') . '</p></div>'; } // Get current settings $tracking_enabled = get_option('bdfg_tracking_enabled', 1); $data_retention = get_option('bdfg_data_retention_days', 365); $dashboard_widgets = get_option('bdfg_dashboard_widgets', 1); $tracking_location = get_option('bdfg_tracking_location', 'all'); ?> <div class="wrap bdfg-analytics-wrap"> <h1><?php _e('BDFG Product Analytics Settings', 'bdfg-product-analytics'); ?></h1> <form method="post" action=""> <?php wp_nonce_field('bdfg_settings_save', 'bdfg_settings_nonce'); ?> <table class="form-table"> <tr> <th scope="row"><?php _e('Enable Tracking', 'bdfg-product-analytics'); ?></th> <td> <label> <input type="checkbox" name="bdfg_tracking_enabled" value="1" <?php checked($tracking_enabled, 1); ?>> <?php _e('Track product impressions and clicks', 'bdfg-product-analytics'); ?> </label> <p class="description"><?php _e('Disable this if you want to temporarily stop collecting analytics data.', 'bdfg-product-analytics'); ?></p> </td> </tr> <tr> <th scope="row"><?php _e('Data Retention Period', 'bdfg-product-analytics'); ?></th> <td> <input type="number" name="bdfg_data_retention_days" value="<?php echo esc_attr($data_retention); ?>" min="1" max="3650" step="1"> <?php _e('days', 'bdfg-product-analytics'); ?> <p class="description"><?php _e('Conversion data older than this will be deleted automatically. Set to 0 to keep data indefinitely (not recommended for large stores).', 'bdfg-product-analytics'); ?></p> </td> </tr> <tr> <th scope="row"><?php _e('Dashboard Widgets', 'bdfg-product-analytics'); ?></th> <td> <label> <input type="checkbox" name="bdfg_dashboard_widgets" value="1" <?php checked($dashboard_widgets, 1); ?>> <?php _e('Show analytics summary on WordPress dashboard', 'bdfg-product-analytics'); ?> </label> <p class="description"><?php _e('Displays a widget with key analytics metrics on the WordPress admin dashboard.', 'bdfg-product-analytics'); ?></p> </td> </tr> <tr> <th scope="row"><?php _e('Tracking Location', 'bdfg-product-analytics'); ?></th> <td> <select name="bdfg_tracking_location"> <option value="all" <?php selected($tracking_location, 'all'); ?>><?php _e('All product pages', 'bdfg-product-analytics'); ?></option> <option value="shop" <?php selected($tracking_location, 'shop'); ?>><?php _e('Shop pages only', 'bdfg-product-analytics'); ?></option> <option value="product" <?php selected($tracking_location, 'product'); ?>><?php _e('Single product pages only', 'bdfg-product-analytics'); ?></option> </select> <p class="description"><?php _e('Choose where to track product impressions.', 'bdfg-product-analytics'); ?></p> </td> </tr> </table> <h2><?php _e('Advanced Settings', 'bdfg-product-analytics'); ?></h2> <table class="form-table"> <tr> <th scope="row"><?php _e('Database Maintenance', 'bdfg-product-analytics'); ?></th> <td> <p> <a href="<?php echo wp_nonce_url(admin_url('admin.php?page=bdfg-product-analytics-settings&bdfg_action=optimize_tables'), 'bdfg_optimize_tables'); ?>" class="button"> <?php _e('Optimize Database Tables', 'bdfg-product-analytics'); ?> </a> </p> <p class="description"><?php _e('Optimizes the analytics database tables to improve performance.', 'bdfg-product-analytics'); ?></p> </td> </tr> <tr> <th scope="row"><?php _e('Reset Analytics Data', 'bdfg-product-analytics'); ?></th> <td> <p> <a href="<?php echo wp_nonce_url(admin_url('admin.php?page=bdfg-product-analytics-settings&bdfg_action=reset_data'), 'bdfg_reset_data'); ?>" class="button button-danger" onclick="return confirm('<?php esc_attr_e('WARNING: This will permanently delete all analytics data. This action cannot be undone. Are you sure?', 'bdfg-product-analytics'); ?>');"> <?php _e('Reset All Data', 'bdfg-product-analytics'); ?> </a> </p> <p class="description"><?php _e('WARNING: This will delete all impression, click, and conversion data. This action cannot be undone.', 'bdfg-product-analytics'); ?></p> </td> </tr> </table> <p class="submit"> <input type="submit" name="bdfg_save_settings" class="button button-primary" value="<?php esc_attr_e('Save Settings', 'bdfg-product-analytics'); ?>"> </p> </form> <div class="bdfg-settings-sidebar"> <div class="bdfg-settings-box"> <h3><?php _e('About BDFG Product Analytics', 'bdfg-product-analytics'); ?></h3> <p><?php _e('BDFG Product Analytics helps you understand how customers interact with your products by tracking impressions, clicks, and conversions.', 'bdfg-product-analytics'); ?></p> <p><?php printf(__('Version: %s', 'bdfg-product-analytics'), BDFG_PRODUCT_ANALYTICS_VERSION); ?></p> <p><a href="https://beiduofengou.net/docs/product-analytics/" target="_blank"><?php _e('Documentation', 'bdfg-product-analytics'); ?></a> | <a href="https://beiduofengou.net/support/" target="_blank"><?php _e('Support', 'bdfg-product-analytics'); ?></a></p> </div> <div class="bdfg-settings-box"> <h3><?php _e('Need More Features?', 'bdfg-product-analytics'); ?></h3> <p><?php _e('Check out our premium extensions for BDFG Product Analytics:', 'bdfg-product-analytics'); ?></p> <ul class="bdfg-features-list"> <li><?php _e('Advanced Reporting Suite', 'bdfg-product-analytics'); ?></li> <li><?php _e('Customer Journey Tracking', 'bdfg-product-analytics'); ?></li> <li><?php _e('A/B Testing for Products', 'bdfg-product-analytics'); ?></li> <li><?php _e('AI-powered Product Recommendations', 'bdfg-product-analytics'); ?></li> </ul> <p><a href="https://beiduofengou.net/products/extensions/" target="_blank" class="button button-primary"><?php _e('View Extensions', 'bdfg-product-analytics'); ?></a></p> </div> </div> <div class="bdfg-footer"> <p><?php printf(__('BDFG Product Analytics v%s | Settings last updated: %s | Current user: %s', 'bdfg-product-analytics'), BDFG_PRODUCT_ANALYTICS_VERSION, '2025-03-06 10:18:50', 'beiduofengou'); ?></p> </div> </div> <?php } }
assets/js/frontend.js
相关文章: WordPress 智能缓存管理
/** * BDFG Product Analytics - Frontend JS * * Handles tracking of impressions and clicks * * @package BDFG_Product_Analytics * @since 2.1.0 */ (function($) { 'use strict'; // Make sure we have jQuery and our data object if (typeof $ !== 'function' || typeof bdfgAnalytics === 'undefined') { return; } var BDFG_Frontend = { // Store tracked product IDs to avoid duplicates trackedImpressions: [], trackedClicks: [], /** * Initialize frontend tracking */ init: function() { // Track impressions after a short delay to ensure elements are rendered setTimeout(this.trackImpressions, bdfgAnalytics.delay || 1000); // Track clicks on product links $(document).on('click', 'a[data-bdfg-product-id]', this.trackClick); if (bdfgAnalytics.debug) { console.log('BDFG Analytics: Tracking initialized'); } }, /** * Track product impressions */ trackImpressions: function() { $('.bdfg-product-impression').each(function() { var $this = $(this); var productId = $this.data('product-id'); // Skip if already tracked or invalid if (!productId || BDFG_Frontend.trackedImpressions.includes(productId)) { return; } // Add to tracked list BDFG_Frontend.trackedImpressions.push(productId); // Send AJAX request $.post({ url: bdfgAnalytics.ajax_url, data: { action: 'bdfg_track_impression', nonce: bdfgAnalytics.nonce, product_id: productId }, success: function(response) { if (bdfgAnalytics.debug && response.success) { console.log('BDFG Analytics: Tracked impression for product ID ' + productId); } } }); }); }, /** * Track product click * * @param {Event} e Click event */ trackClick: function(e) { var $this = $(this); var productId = $this.data('bdfg-product-id'); // Skip if already tracked or invalid if (!productId || BDFG_Frontend.trackedClicks.includes(productId)) { return; } // Add to tracked list BDFG_Frontend.trackedClicks.push(productId); // Send AJAX request (don't block navigation) $.post({ url: bdfgAnalytics.ajax_url, data: { action: 'bdfg_track_click', nonce: bdfgAnalytics.nonce, product_id: productId }, success: function(response) { if (bdfgAnalytics.debug && response.success) { console.log('BDFG Analytics: Tracked click for product ID ' + productId); } } }); } }; // Initialize on document ready $(document).ready(function() { BDFG_Frontend.init(); }); })(jQuery);
assets/js/admin.js
/** * BDFG Product Analytics - Admin JS * * Handles admin charts and functionality * * @package BDFG_Product_Analytics * @since 2.1.0 */ (function($) { 'use strict'; // Make sure we have jQuery and Chart.js if (typeof $ !== 'function' || typeof Chart === 'undefined' || typeof bdfgAnalytics === 'undefined') { return; } var BDFG_Admin = { /** * Initialize admin functionality */ init: function() { this.initCharts(); this.initEventHandlers(); // Custom brand colors for charts Chart.defaults.color = '#666'; Chart.defaults.font.family = '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif'; }, /** * Initialize charts if they exist */ initCharts: function() { if ($('#bdfg-ctr-chart').length) { this.createCTRChart(); } if ($('#bdfg-clicks-chart').length) { this.createClicksChart(); } }, /** * Initialize event handlers */ initEventHandlers: function() { $('.bdfg-export-button a').on('click', function(e) { // Track export action // (Just a stub for now) }); // DateRange picker if we have it if ($.fn.daterangepicker && $('.bdfg-daterange-picker').length) { $('.bdfg-daterange-picker').daterangepicker({ ranges: { 'Today': [moment(), moment()], 'Yesterday': [moment().subtract(1, 'days'), moment().subtract(1, 'days')], 'Last 7 Days': [moment().subtract(6, 'days'), moment()], 'Last 30 Days': [moment().subtract(29, 'days'), moment()], 'This Month': [moment().startOf('month'), moment().endOf('month')], 'Last Month': [moment().subtract(1, 'month').startOf('month'), moment().subtract(1, 'month').endOf('month')] }, alwaysShowCalendars: true, startDate: moment().subtract(29, 'days'), endDate: moment(), locale: { format: 'YYYY-MM-DD' } }); } }, /** * Create CTR chart */ createCTRChart: function() { var ctx = document.getElementById('bdfg-ctr-chart').getContext('2d'); var labels = []; var ctrData = []; var colors = []; // Extract data from our global object for (var i = 0; i < bdfgAnalytics.products.length; i++) { var product = bdfgAnalytics.products[i]; labels.push(product.name); ctrData.push(product.ctr); // Custom gradient colors based on CTR value if (product.ctr < 2) { colors.push('#ff7675'); // Low CTR } else if (product.ctr < 5) { colors.push('#fdcb6e'); // Medium CTR } else { colors.push('#00b894'); // High CTR } } new Chart(ctx, { type: 'bar', data: { labels: labels, datasets: [{ label: bdfgAnalytics.translations.ctr + ' (%)', data: ctrData, backgroundColor: colors, borderWidth: 1 }] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { display: false }, tooltip: { callbacks: { label: function(context) { return context.raw + '%'; } } } }, scales: { y: { beginAtZero: true, ticks: { callback: function(value) { return value + '%'; } }, title: { display: true, text: bdfgAnalytics.translations.ctr } } } } }); }, /** * Create impressions vs clicks chart */ createClicksChart: function() { var ctx = document.getElementById('bdfg-clicks-chart').getContext('2d'); var labels = []; var impressionsData = []; var clicksData = []; // Extract data from our global object for (var i = 0; i < bdfgAnalytics.products.length; i++) { var product = bdfgAnalytics.products[i]; labels.push(product.name); impressionsData.push(product.impressions); clicksData.push(product.clicks); } new Chart(ctx, { type: 'bar', data: { labels: labels, datasets: [ { label: bdfgAnalytics.translations.impressions, data: impressionsData, backgroundColor: 'rgba(54, 162, 235, 0.5)', borderColor: 'rgba(54, 162, 235, 1)', borderWidth: 1 }, { label: bdfgAnalytics.translations.clicks, data: clicksData, backgroundColor: 'rgba(255, 159, 64, 0.5)', borderColor: 'rgba(255, 159, 64, 1)', borderWidth: 1 } ] }, options: { responsive: true, maintainAspectRatio: false, plugins: { title: { display: true, text: bdfgAnalytics.translations.impressions + ' vs ' + bdfgAnalytics.translations.clicks }, tooltip: { mode: 'index', intersect: false } }, scales: { y: { beginAtZero: true, title: { display: true, text: 'Count' } } } } }); } }; // Initialize on document ready $(document).ready(function() { BDFG_Admin.init(); }); })(jQuery);
assets/css/admin.css
/** * BDFG Product Analytics - Admin styles * * @package BDFG_Product_Analytics * @since 2.1.0 * @author Bei Duo Feng Ou */ /* Dashboard layout */ .bdfg-analytics-wrap { margin: 20px 0; max-width: 1200px; } /* Time range selector */ .bdfg-time-range { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; background-color: #fff; padding: 15px; border-radius: 3px; box-shadow: 0 1px 3px rgba(0,0,0,0.1); } .bdfg-time-range select { min-width: 180px; } /* Summary cards */ .bdfg-summary-cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 20px; margin-bottom: 30px; } .bdfg-card { background-color: #fff; border-radius: 4px; box-shadow: 0 1px 3px rgba(0,0,0,0.1); padding: 20px; text-align: center; transition: all 0.3s ease; } .bdfg-card:hover { transform: translateY(-3px); box-shadow: 0 4px 6px rgba(0,0,0,0.1); } .bdfg-card-content h3 { margin: 0 0 10px 0; font-size: 14px; color: #777; font-weight: normal; } .bdfg-card-value { font-size: 24px; font-weight: bold; color: #333; margin-bottom: 10px; } .bdfg-card-description { font-size: 12px; color: #777; } /* Charts container */ .bdfg-charts-container { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; margin-bottom: 30px; } @media (max-width: 960px) { .bdfg-charts-container { grid-template-columns: 1fr; } } .bdfg-chart-card { background-color: #fff; border-radius: 4px; box-shadow: 0 1px 3px rgba(0,0,0,0.1); padding: 20px; } .bdfg-chart-card h2 { margin-top: 0; font-size: 16px; border-bottom: 1px solid #eee; padding-bottom: 10px; margin-bottom: 20px; } .bdfg-chart-container { position: relative; height: 300px; } /* Table styling */ .bdfg-table-container { background-color: #fff; border-radius: 4px; box-shadow: 0 1px 3px rgba(0,0,0,0.1); padding: 20px; margin-bottom: 30px; } .bdfg-table-container h2 { margin-top: 0; font-size: 18px; border-bottom: 1px solid #eee; padding-bottom: 15px; margin-bottom: 20px; } .bdfg-view-more { text-align: right; margin-top: 20px; } /* Footer */ .bdfg-footer { text-align: center; color: #777; font-size: 12px; margin-top: 40px; } /* Product analytics section in product data metabox */ .bdfg-analytics-section { border: 1px solid #eee; border-radius: 3px; padding: 10px; margin-top: 10px; background: #f9f9f9; } .bdfg-analytics-section h4 { margin-top: 0; color: #0073aa; } /* Dashboard widget styling */ .bdfg-dashboard-widget { padding: 0; } .bdfg-widget-summary { display: flex; justify-content: space-between; margin-bottom: 15px; } .bdfg-widget-stat { text-align: center; padding: 10px; flex: 1; } .bdfg-stat-value { display: block; font-size: 18px; font-weight: bold; color: #0073aa; } .bdfg-stat-label { display: block; font-size: 11px; color: #777; } .bdfg-widget-footer { text-align: right; border-top: 1px solid #eee; padding-top: 12px; margin: 0; } /* Settings page specific */ .bdfg-settings-wrap { max-width: 1200px; margin-top: 20px; display: flex; flex-wrap: wrap; } .bdfg-settings-wrap form { flex: 1 1 65%; margin-right: 30px; } .bdfg-settings-sidebar { flex: 0 0 30%; min-width: 250px; } .bdfg-settings-box { background: #fff; border: 1px solid #ccd0d4; box-shadow: 0 1px 1px rgba(0,0,0,0.04); margin-bottom: 20px; padding: 15px; } .bdfg-settings-box h3 { margin-top: 0; padding-bottom: 10px; border-bottom: 1px solid #eee; } .bdfg-features-list { margin: 0; padding: 0; list-style-type: none; } .bdfg-features-list li { padding: 8px 0 8px 24px; position: relative; } .bdfg-features-list li:before { content: "✓"; position: absolute; left: 0; color: #0073aa; font-weight: bold; } .button-danger { background: #ca4a1f !important; border-color: #aa341f !important; color: #fff !important; } .button-danger:hover { background: #aa341f !important; } /* Product specific page */ .bdfg-product-header { display: flex; align-items: center; margin-bottom: 30px; background: #fff; padding: 20px; border-radius: 4px; box-shadow: 0 1px 3px rgba(0,0,0,0.1); } .bdfg-product-image { margin-right: 20px; flex: 0 0 80px; } .bdfg-product-info h2 { margin-top: 0; margin-bottom: 10px; } .bdfg-product-sku, .bdfg-product-price { margin: 0 0 10px 0; color: #777; } /* Recommendation cards */ .bdfg-recommendation-card { background-color: #fff; border-left: 4px solid #0073aa; border-radius: 4px; box-shadow: 0 1px 3px rgba(0,0,0,0.1); padding: 20px; margin-bottom: 20px; } .bdfg-recommendation-card h3 { margin-top: 0; color: #0073aa; } .bdfg-recommendation-card p { margin-bottom: 0; } /* Filters */ .bdfg-filters { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; background-color: #fff; padding: 15px; border-radius: 3px; box-shadow: 0 1px 3px rgba(0,0,0,0.1); margin-bottom: 20px; } .bdfg-filters form { display: flex; flex-wrap: wrap; align-items: center; gap: 15px; } .bdfg-filter-group { display: flex; align-items: center; } .bdfg-filter-group label { margin-right: 10px; font-weight: bold; } /* BDFG branding specific */ .bdfg-brand-header { padding: 15px; background: linear-gradient(135deg, #0073aa 0%, #006291 100%); color: #fff; border-radius: 4px; margin-bottom: 20px; } .bdfg-brand-header h1 { color: #fff; margin-top: 0; } .bdfg-brand-footer { margin-top: 40px; padding: 15px; background: #f7f7f7; border-radius: 4px; text-align: center; } /* Custom badge for BDFG products */ .bdfg-badge { display: inline-block; background: linear-gradient(135deg, #0073aa 0%, #006291 100%); color: #fff; font-size: 10px; font-weight: bold; text-transform: uppercase; padding: 3px 8px; border-radius: 10px; vertical-align: middle; margin-left: 5px; }
templates/admin.php
<?php /** * BDFG Product Analytics - Admin dashboard template * * @package BDFG_Product_Analytics * @since 2.1.0 */ // Exit if accessed directly if (!defined('ABSPATH')) { exit; } ?> <div class="wrap bdfg-analytics-wrap"> <div class="bdfg-brand-header"> <h1><?php _e('BDFG Product Analytics Dashboard', 'bdfg-product-analytics'); ?></h1> <p><?php _e('Understand how customers interact with your products to optimize your catalog for better conversions.', 'bdfg-product-analytics'); ?></p> </div> <div class="bdfg-time-range"> <form method="get"> <input type="hidden" name="page" value="bdfg-product-analytics"> <select name="range" onchange="this.form.submit()"> <option value="7d" <?php selected($time_range, '7d'); ?>><?php _e('Last 7 Days', 'bdfg-product-analytics'); ?></option> <option value="30d" <?php selected($time_range, '30d'); ?>><?php _e('Last 30 Days', 'bdfg-product-analytics'); ?></option> <option value="90d" <?php selected($time_range, '90d'); ?>><?php _e('Last 90 Days', 'bdfg-product-analytics'); ?></option> <option value="year" <?php selected($time_range, 'year'); ?>><?php _e('Last Year', 'bdfg-product-analytics'); ?></option> <option value="all" <?php selected($time_range, 'all'); ?>><?php _e('All Time', 'bdfg-product-analytics'); ?></option> </select> </form> <div class="bdfg-export-button"> <a href="<?php echo wp_nonce_url(admin_url('admin-ajax.php?action=bdfg_export_analytics&range=' . $time_range), 'bdfg_export_analytics'); ?>" class="button"> <span class="dashicons dashicons-download" style="margin-top: 3px;"></span> <?php _e('Export to CSV', 'bdfg-product-analytics'); ?> </a> </div> </div> <?php // Get analytics summary $summary = bdfg_get_analytics_summary($time_range); ?> <div class="bdfg-summary-cards"> <div class="bdfg-card"> <div class="bdfg-card-content"> <h3><?php _e('Impressions', 'bdfg-product-analytics'); ?></h3> <div class="bdfg-card-value"><?php echo number_format($summary->total_impressions); ?></div> <div class="bdfg-card-description"><?php _e('Total product views', 'bdfg-product-analytics'); ?></div> </div> </div> <div class="bdfg-card"> <div class="bdfg-card-content"> <h3><?php _e('Clicks', 'bdfg-product-analytics'); ?></h3> <div class="bdfg-card-value"><?php echo number_format($summary->total_clicks); ?></div> <div class="bdfg-card-description"><?php _e('Total product clicks', 'bdfg-product-analytics'); ?></div> </div> </div> <div class="bdfg-card"> <div class="bdfg-card-content"> <h3><?php _e('CTR', 'bdfg-product-analytics'); ?></h3> <div class="bdfg-card-value"><?php echo $summary->total_ctr; ?>%</div> <div class="bdfg-card-description"><?php _e('Click-through rate', 'bdfg-product-analytics'); ?></div> </div> </div> <div class="bdfg-card"> <div class="bdfg-card-content"> <h3><?php _e('Conversions', 'bdfg-product-analytics'); ?></h3> <div class="bdfg-card-value"><?php echo number_format($summary->total_conversions); ?></div> <div class="bdfg-card-description"><?php _e('Total purchases', 'bdfg-product-analytics'); ?></div> </div> </div> <div class="bdfg-card"> <div class="bdfg-card-content"> <h3><?php _e('Revenue', 'bdfg-product-analytics'); ?></h3> <div class="bdfg-card-value"><?php echo wc_price($summary->total_revenue); ?></div> <div class="bdfg-card-description"><?php _e('Total sales value', 'bdfg-product-analytics'); ?></div> </div> </div> </div> <div class="bdfg-charts-container"> <div class="bdfg-chart-card"> <h2><?php _e('Top Performing Products by CTR', 'bdfg-product-analytics'); ?></h2> <div class="bdfg-chart-container"> <canvas id="bdfg-ctr-chart"></canvas> </div> </div> <div class="bdfg-chart-card"> <h2><?php _e('Impressions vs Clicks', 'bdfg-product-analytics'); ?></h2> <div class="bdfg-chart-container"> <canvas id="bdfg-clicks-chart"></canvas> </div> </div> </div> <div class="bdfg-table-container"> <h2><?php _e('Top Products by CTR', 'bdfg-product-analytics'); ?></h2> <table class="wp-list-table widefat fixed striped"> <thead> <tr> <th><?php _e('Product', 'bdfg-product-analytics'); ?></th> <th><?php _e('Impressions', 'bdfg-product-analytics'); ?></th> <th><?php _e('Clicks', 'bdfg-product-analytics'); ?></th> <th><?php _e('CTR', 'bdfg-product-analytics'); ?></th> <th><?php _e('Conversions', 'bdfg-product-analytics'); ?></th> <th><?php _e('Revenue', 'bdfg-product-analytics'); ?></th> </tr> </thead> <tbody> <?php if (empty($stats)) : ?> <tr> <td colspan="6"><?php _e('No product data available yet. Data will appear once customers start viewing your products.', 'bdfg-product-analytics'); ?></td> </tr> <?php else : ?> <?php foreach ($stats as $product) : $ctr = ($product->impressions > 0) ? round(($product->clicks / $product->impressions) * 100, 2) : 0; ?> <tr> <td> <a href="<?php echo admin_url('post.php?post=' . $product->product_id . '&action=edit'); ?>"> <?php echo get_the_title($product->product_id); ?> </a> <div class="row-actions"> <span class="view"> <a href="<?php echo admin_url('admin.php?page=bdfg-product-analytics-reports&product=' . $product->product_id); ?>"><?php _e('View Analytics', 'bdfg-product-analytics'); ?></a> </span> </div> </td> <td><?php echo number_format($product->impressions); ?></td> <td><?php echo number_format($product->clicks); ?></td> <td><?php echo $ctr; ?>%</td> <td><?php echo number_format($product->conversions); ?></td> <td><?php echo wc_price($product->revenue); ?></td> </tr> <?php endforeach; ?> <?php endif; ?> </tbody> </table> <p class="bdfg-view-more"> <a href="<?php echo admin_url('admin.php?page=bdfg-product-analytics-reports'); ?>" class="button button-primary"> <?php _e('View All Products Analytics', 'bdfg-product-analytics'); ?> </a> </p> </div> <div class="bdfg-brand-footer"> <p><?php printf(__('BDFG Product Analytics v%s | Data as of %s | Generated by %s', 'bdfg-product-analytics'), BDFG_PRODUCT_ANALYTICS_VERSION, '2025-03-06 11:07:34', 'beiduofengou'); ?></p> <p><a href="https://beiduofengou.net/" target="_blank"><?php _e('Visit beiduofengou.net for more premium WordPress plugins', 'bdfg-product-analytics'); ?></a></p> </div> </div>
templates/settings.php
<?php /** * BDFG Product Analytics - Settings template * * @package BDFG_Product_Analytics * @since 2.1.0 */ // Exit if accessed directly if (!defined('ABSPATH')) { exit; } // Get current settings $tracking_enabled = get_option('bdfg_tracking_enabled', 1); $data_retention = get_option('bdfg_data_retention_days', 365); $dashboard_widgets = get_option('bdfg_dashboard_widgets', 1); $tracking_location = get_option('bdfg_tracking_location', 'all'); ?> <div class="wrap bdfg-analytics-wrap"> <div class="bdfg-brand-header"> <h1><?php _e('BDFG Product Analytics Settings', 'bdfg-product-analytics'); ?></h1> <p><?php _e('Configure your product analytics settings to optimize data collection and reporting.', 'bdfg-product-analytics'); ?></p> </div> <div class="bdfg-settings-wrap"> <form method="post" action=""> <?php wp_nonce_field('bdfg_settings_save', 'bdfg_settings_nonce'); ?> <div class="bdfg-settings-section"> <h2><?php _e('General Settings', 'bdfg-product-analytics'); ?></h2> <table class="form-table"> <tr> <th scope="row"><?php _e('Enable Tracking', 'bdfg-product-analytics'); ?></th> <td> <label for="bdfg_tracking_enabled"> <input type="checkbox" name="bdfg_tracking_enabled" id="bdfg_tracking_enabled" value="1" <?php checked($tracking_enabled, 1); ?>> <?php _e('Track product impressions and clicks', 'bdfg-product-analytics'); ?> </label> <p class="description"><?php _e('Disable this if you want to temporarily stop collecting analytics data.', 'bdfg-product-analytics'); ?></p> </td> </tr> <tr> <th scope="row"><?php _e('Data Retention Period', 'bdfg-product-analytics'); ?></th> <td> <input type="number" name="bdfg_data_retention_days" id="bdfg_data_retention_days" value="<?php echo esc_attr($data_retention); ?>" min="1" max="3650" step="1"> <?php _e('days', 'bdfg-product-analytics'); ?> <p class="description"><?php _e('Conversion data older than this will be deleted automatically. Set to 0 to keep data indefinitely (not recommended for large stores).', 'bdfg-product-analytics'); ?></p> </td> </tr> <tr> <th scope="row"><?php _e('Dashboard Widgets', 'bdfg-product-analytics'); ?></th> <td> <label for="bdfg_dashboard_widgets"> <input type="checkbox" name="bdfg_dashboard_widgets" id="bdfg_dashboard_widgets" value="1" <?php checked($dashboard_widgets, 1); ?>> <?php _e('Show analytics summary on WordPress dashboard', 'bdfg-product-analytics'); ?> </label> <p class="description"><?php _e('Displays a widget with key analytics metrics on the WordPress admin dashboard.', 'bdfg-product-analytics'); ?></p> </td> </tr> <tr> <th scope="row"><?php _e('Tracking Location', 'bdfg-product-analytics'); ?></th> <td> <select name="bdfg_tracking_location" id="bdfg_tracking_location"> <option value="all" <?php selected($tracking_location, 'all'); ?>><?php _e('All product pages', 'bdfg-product-analytics'); ?></option> <option value="shop" <?php selected($tracking_location, 'shop'); ?>><?php _e('Shop pages only', 'bdfg-product-analytics'); ?></option> <option value="product" <?php selected($tracking_location, 'product'); ?>><?php _e('Single product pages only', 'bdfg-product-analytics'); ?></option> </select> <p class="description"><?php _e('Choose where to track product impressions.', 'bdfg-product-analytics'); ?></p> </td> </tr> </table> </div> <div class="bdfg-settings-section"> <h2><?php _e('Advanced Settings', 'bdfg-product-analytics'); ?></h2> <table class="form-table"> <tr> <th scope="row"><?php _e('Database Maintenance', 'bdfg-product-analytics'); ?></th> <td> <p> <a href="<?php echo wp_nonce_url(admin_url('admin.php?page=bdfg-product-analytics-settings&bdfg_action=optimize_tables'), 'bdfg_optimize_tables'); ?>" class="button"> <?php _e('Optimize Database Tables', 'bdfg-product-analytics'); ?> </a> </p> <p class="description"><?php _e('Optimizes the analytics database tables to improve performance.', 'bdfg-product-analytics'); ?></p> </td> </tr> <tr> <th scope="row"><?php _e('Reset Analytics Data', 'bdfg-product-analytics'); ?></th> <td> <p> <a href="<?php echo wp_nonce_url(admin_url('admin.php?page=bdfg-product-analytics-settings&bdfg_action=reset_data'), 'bdfg_reset_data'); ?>" class="button button-danger" onclick="return confirm('<?php esc_attr_e('WARNING: This will permanently delete all analytics data. This action cannot be undone. Are you sure?', 'bdfg-product-analytics'); ?>');"> <?php _e('Reset All Data', 'bdfg-product-analytics'); ?> </a> </p> <p class="description"><?php _e('WARNING: This will delete all impression, click, and conversion data. This action cannot be undone.', 'bdfg-product-analytics'); ?></p> </td> </tr> </table> </div> <p class="submit"> <input type="submit" name="bdfg_save_settings" class="button button-primary" value="<?php esc_attr_e('Save Settings', 'bdfg-product-analytics'); ?>"> </p> </form> <div class="bdfg-settings-sidebar"> <div class="bdfg-settings-box"> <h3><?php _e('About BDFG Product Analytics', 'bdfg-product-analytics'); ?></h3> <p><?php _e('BDFG Product Analytics helps you understand how customers interact with your products by tracking impressions, clicks, and conversions.', 'bdfg-product-analytics'); ?></p> <p><?php printf(__('Version: %s', 'bdfg-product-analytics'), BDFG_PRODUCT_ANALYTICS_VERSION); ?></p> <p><a href="https://beiduofengou.net/docs/product-analytics/" target="_blank"><?php _e('Documentation', 'bdfg-product-analytics'); ?></a> | <a href="https://beiduofengou.net/support/" target="_blank"><?php _e('Support', 'bdfg-product-analytics'); ?></a></p> </div> <div class="bdfg-settings-box"> <h3><?php _e('Need More Features?', 'bdfg-product-analytics'); ?></h3> <p><?php _e('Check out our premium extensions for BDFG Product Analytics:', 'bdfg-product-analytics'); ?></p> <ul class="bdfg-features-list"> <li><?php _e('Advanced Reporting Suite', 'bdfg-product-analytics'); ?></li> <li><?php _e('Customer Journey Tracking', 'bdfg-product-analytics'); ?></li> <li><?php _e('A/B Testing for Products', 'bdfg-product-analytics'); ?></li> <li><?php _e('AI-powered Product Recommendations', 'bdfg-product-analytics'); ?></li> </ul> <p><a href="https://beiduofengou.net/products/extensions/" target="_blank" class="button button-primary"><?php _e('View Extensions', 'bdfg-product-analytics'); ?></a></p> </div> </div> </div> <div class="bdfg-brand-footer"> <p><?php printf(__('BDFG Product Analytics v%s | Settings last updated: %s | Current user: %s', 'bdfg-product-analytics'), BDFG_PRODUCT_ANALYTICS_VERSION, '2025-03-06 11:10:56', 'beiduofengou'); ?></p> </div> </div>