woocommerce产品分析插件

对客户如何与您的产品互动的深入洞察。通过跟踪展示次数、点击次数和转化次数,您可以了解哪些产品表现最佳,并相应地优化您的目录。

### 主要功能
* **展示次数跟踪**:跟踪每件产品的浏览次数
* **点击跟踪**:通过跟踪产品点击次数来监控用户参与度
* **点击率计算**:计算点击率以识别表现优异的产品
* **转化跟踪**:跟踪产品的购买时间
* **详细报告**:使用可排序的表格和图表查看全面的分析
* **仪表板小部件**:直接在 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>

 

Leave a Comment