WooCommerce 客户分析报告插件

为WooCommerce商店生成高级客户分析和报告。

<?php
/**
* Plugin Name: BDFG Customer Analytics for WooCommerce
* Plugin URI: https://beiduofengou.net/2024/05/15/bdfg-customer-analytics-for-woocommerce/
* Description: Generate advanced customer analytics and reports for WooCommerce stores. Created by beiduofengou.
* Version: 2.0.1
* Author: beiduofengou
* Author URI: https://beiduofengou.net
* Text Domain: bdfg-customer-analytics
* Domain Path: /languages
* Requires at least: 5.8
* Requires PHP: 7.4
* WC requires at least: 5.0
* WC tested up to: 8.0
* License: GPL v2 or later
*/

// 防止直接访问
defined('ABSPATH') || exit;

// 定义插件常量
define('BDFG_CA_VERSION', '2.0.1');
define('BDFG_CA_PLUGIN_DIR', plugin_dir_path(__FILE__));
define('BDFG_CA_PLUGIN_URL', plugin_dir_url(__FILE__));
define('BDFG_CA_MIN_WP_VERSION', '5.8');
define('BDFG_CA_MIN_PHP_VERSION', '7.4');

// 自动加载插件类
spl_autoload_register(function ($class) {
// 检查类名是否以BDFG_开头
if (strpos($class, 'BDFG_') !== 0) {
return;
}

// 转换类名为文件路径
$file = str_replace('BDFG_', '', $class);
$file = str_replace('_', '-', strtolower($file));
$path = BDFG_CA_PLUGIN_DIR . 'includes/class-' . $file . '.php';

if (file_exists($path)) {
require_once $path;
}
});

// 初始化主插件类
function bdfg_customer_analytics_init() {
// 检查基本要求
if (!bdfg_ca_check_requirements()) {
return;
}

// 加载文本域
load_plugin_textdomain('bdfg-customer-analytics', false, dirname(plugin_basename(__FILE__)) . '/languages');

// 初始化插件实例
BDFG_Customer_Analytics::get_instance();
}

// 检查插件运行要求
function bdfg_ca_check_requirements() {
global $wp_version;

if (version_compare(PHP_VERSION, BDFG_CA_MIN_PHP_VERSION, '<')) {
add_action('admin_notices', function() {
printf('<div class="error"><p>%s</p></div>',
sprintf(__('BDFG Customer Analytics 需要 PHP %s 或更高版本。', 'bdfg-customer-analytics'),
BDFG_CA_MIN_PHP_VERSION)
);
});
return false;
}

if (version_compare($wp_version, BDFG_CA_MIN_WP_VERSION, '<')) {
add_action('admin_notices', function() {
printf('<div class="error"><p>%s</p></div>',
sprintf(__('BDFG Customer Analytics 需要 WordPress %s 或更高版本。', 'bdfg-customer-analytics'),
BDFG_CA_MIN_WP_VERSION)
);
});
return false;
}

if (!class_exists('WooCommerce')) {
add_action('admin_notices', function() {
echo '<div class="error"><p>' .
__('BDFG Customer Analytics 需要 WooCommerce 插件。请先安装并激活 WooCommerce。', 'bdfg-customer-analytics') .
'</p></div>';
});
return false;
}

return true;
}

// 在所有插件加载后初始化
add_action('plugins_loaded', 'bdfg_customer_analytics_init');

// 激活插件时的处理
register_activation_hook(__FILE__, function() {
require_once BDFG_CA_PLUGIN_DIR . 'includes/class-activator.php';
BDFG_Customer_Analytics_Activator::activate();
});

// 停用插件时的处理
register_deactivation_hook(__FILE__, function() {
require_once BDFG_CA_PLUGIN_DIR . 'includes/class-deactivator.php';
BDFG_Customer_Analytics_Deactivator::deactivate();
});

includes/class-customer-analytics.php

相关文章: WordPress 地图定位插件

<?php
/**
* BDFG Customer Analytics 主类
*
* @package BDFG_Customer_Analytics
* @version 2.0.1
* @since 2.0.0
* @author Bei Duo Feng Ou <[email protected]>
*/

defined('ABSPATH') || exit;

class BDFG_Customer_Analytics {
/**
* 插件实例
*
* @var BDFG_Customer_Analytics
*/
private static $instance = null;

/**
* 缓存过期时间(秒)
*
* @var int
*/
private $cache_expiry = 3600;

/**
* 图表默认颜色
*
* @var array
*/
private $chart_colors = [
'#2271b1',
'#72aee6',
'#00a0d2',
'#04a4cc'
];

/**
* 获取插件实例
*
* @return BDFG_Customer_Analytics
*/
public static function get_instance() {
if (null === self::$instance) {
self::$instance = new self();
}
return self::$instance;
}

/**
* 构造函数 - 设置钩子和过滤器
*/
private function __construct() {
// 初始化模块
$this->init_modules();

// 添加菜单和资源
add_action('admin_menu', array($this, 'add_admin_menu'));
add_action('admin_enqueue_scripts', array($this, 'enqueue_admin_assets'));

// AJAX处理
add_action('wp_ajax_bdfg_get_customer_analytics', array($this, 'handle_ajax_analytics'));
add_action('wp_ajax_bdfg_export_analytics', array($this, 'handle_export_analytics'));
add_action('wp_ajax_bdfg_get_customer_details', array($this, 'handle_customer_details'));

// 添加设置
add_action('admin_init', array($this, 'register_settings'));

// 添加插件操作链接
add_filter(
'plugin_action_links_' . plugin_basename(BDFG_CA_PLUGIN_DIR . 'bdfg-customer-analytics.php'),
array($this, 'add_plugin_links')
);
}

/**
* 初始化插件模块
*/
private function init_modules() {
// 加载必要的类
require_once BDFG_CA_PLUGIN_DIR . 'includes/class-customer-charts.php';
require_once BDFG_CA_PLUGIN_DIR . 'includes/class-customer-segments.php';

new BDFG_Customer_Charts();
new BDFG_Customer_Segments();
}

/**
* 添加管理菜单
*/
public function add_admin_menu() {
add_menu_page(
__('BDFG 客户分析', 'bdfg-customer-analytics'),
__('BDFG 分析', 'bdfg-customer-analytics'),
'manage_woocommerce',
'bdfg-customer-analytics',
array($this, 'render_admin_page'),
'dashicons-chart-area',
56
);

add_submenu_page(
'bdfg-customer-analytics',
__('客户分群', 'bdfg-customer-analytics'),
__('客户分群', 'bdfg-customer-analytics'),
'manage_woocommerce',
'bdfg-customer-segments',
array($this, 'render_segments_page')
);

add_submenu_page(
'bdfg-customer-analytics',
__('设置', 'bdfg-customer-analytics'),
__('设置', 'bdfg-customer-analytics'),
'manage_options',
'bdfg-analytics-settings',
array($this, 'render_settings_page')
);
}

/**
* 加载管理界面资源
*/
public function enqueue_admin_assets($hook) {
if (!$this->is_plugin_page($hook)) {
return;
}

// 样式
wp_enqueue_style(
'bdfg-admin-style',
BDFG_CA_PLUGIN_URL . 'assets/css/admin.css',
array(),
BDFG_CA_VERSION
);

// 日期选择器
wp_enqueue_style('jquery-ui-datepicker');
wp_enqueue_script('jquery-ui-datepicker');

// 主要脚本
wp_enqueue_script(
'bdfg-admin-script',
BDFG_CA_PLUGIN_URL . 'assets/js/admin.js',
array('jquery', 'jquery-ui-datepicker'),
BDFG_CA_VERSION,
true
);

// 本地化脚本
wp_localize_script('bdfg-admin-script', 'bdfgCA', array(
'ajaxUrl' => admin_url('admin-ajax.php'),
'nonce' => wp_create_nonce('bdfg_ca_nonce'),
'i18n' => $this->get_js_translations()
));
}

/**
* 获取JavaScript翻译文本
*/
private function get_js_translations() {
return array(
'loading' => __('正在加载...', 'bdfg-customer-analytics'),
'error' => __('发生错误', 'bdfg-customer-analytics'),
'noData' => __('暂无数据', 'bdfg-customer-analytics'),
'success' => __('操作成功', 'bdfg-customer-analytics'),
'confirm' => __('确定要执行此操作吗?', 'bdfg-customer-analytics')
);
}

/**
* 处理AJAX分析请求
*/
public function handle_ajax_analytics() {
check_ajax_referer('bdfg_ca_nonce', 'nonce');

if (!current_user_can('manage_woocommerce')) {
wp_send_json_error('权限不足');
}

$period = isset($_POST['period']) ? intval($_POST['period']) : 30;
$customer_id = isset($_POST['customer_id']) ? intval($_POST['customer_id']) : 0;

try {
$data = $this->get_analytics_data($customer_id, $period);
wp_send_json_success($data);
} catch (Exception $e) {
wp_send_json_error($e->getMessage());
}
}

/**
* 获取分析数据
*/
private function get_analytics_data($customer_id, $period) {
global $wpdb;

$cache_key = "bdfg_analytics_{$customer_id}_{$period}";
$cached_data = get_transient($cache_key);

if (false !== $cached_data) {
return $cached_data;
}

$date_from = date('Y-m-d', strtotime("-{$period} days"));
$date_to = date('Y-m-d');

// 获取基础统计数据
$stats = $this->get_customer_stats($customer_id, $date_from);

// 获取订单趋势
$trends = $this->get_order_trends($customer_id, $date_from);

// 获取分类统计
$categories = $this->get_category_stats($customer_id, $date_from);

$data = array(
'stats' => $stats,
'trends' => $trends,
'categories' => $categories,
'generated_at' => current_time('mysql')
);

set_transient($cache_key, $data, $this->cache_expiry);

return $data;
}

/**
* 获取客户统计数据
*/
private function get_customer_stats($customer_id, $date_from) {
global $wpdb;

$query = $wpdb->prepare(
"SELECT
COUNT(*) as total_orders,
SUM(pm.meta_value) as total_spent,
AVG(pm.meta_value) as avg_order_value,
MIN(pm.meta_value) as min_order,
MAX(pm.meta_value) as max_order
FROM {$wpdb->posts} as posts
JOIN {$wpdb->postmeta} pm ON posts.ID = pm.post_id
WHERE posts.post_type = 'shop_order'
AND posts.post_status IN ('wc-completed', 'wc-processing')
AND pm.meta_key = '_order_total'
AND posts.post_date >= %s
" . ($customer_id ? "AND posts.post_author = %d" : ""),
$date_from,
$customer_id
);

return $wpdb->get_row($query);
}

/**
* 获取订单趋势数据
*/
private function get_order_trends($customer_id, $date_from) {
global $wpdb;

$query = $wpdb->prepare(
"SELECT
DATE(post_date) as order_date,
COUNT(*) as order_count,
SUM(pm.meta_value) as daily_total
FROM {$wpdb->posts} as posts
JOIN {$wpdb->postmeta} pm ON posts.ID = pm.post_id
WHERE posts.post_type = 'shop_order'
AND posts.post_status IN ('wc-completed', 'wc-processing')
AND pm.meta_key = '_order_total'
AND posts.post_date >= %s
" . ($customer_id ? "AND posts.post_author = %d" : "") . "
GROUP BY DATE(post_date)
ORDER BY order_date ASC",
$date_from,
$customer_id
);

return $wpdb->get_results($query);
}

/**
* 获取分类统计数据
*/
private function get_category_stats($customer_id, $date_from) {
global $wpdb;

$query = $wpdb->prepare(
"SELECT
terms.name as category,
COUNT(DISTINCT order_items.order_item_id) as item_count,
SUM(order_item_meta.meta_value) as category_total
FROM {$wpdb->prefix}woocommerce_order_items as order_items
JOIN {$wpdb->posts} as orders ON order_items.order_id = orders.ID
JOIN {$wpdb->prefix}woocommerce_order_itemmeta as order_item_meta
ON order_items.order_item_id = order_item_meta.order_item_id
JOIN {$wpdb->term_relationships} as term_rels
ON order_item_meta.meta_value = term_rels.object_id
JOIN {$wpdb->term_taxonomy} as tax
ON term_rels.term_taxonomy_id = tax.term_taxonomy_id
JOIN {$wpdb->terms} as terms ON tax.term_id = terms.term_id
WHERE orders.post_type = 'shop_order'
AND orders.post_status IN ('wc-completed', 'wc-processing')
AND orders.post_date >= %s
" . ($customer_id ? "AND orders.post_author = %d" : "") . "
AND tax.taxonomy = 'product_cat'
AND order_item_meta.meta_key = '_product_id'
GROUP BY terms.term_id
ORDER BY item_count DESC
LIMIT 10",
$date_from,
$customer_id
);

return $wpdb->get_results($query);
}

/**
* 渲染管理页面
*/
public function render_admin_page() {
if (!current_user_can('manage_woocommerce')) {
wp_die(__('您没有足够的权限访问此页面。', 'bdfg-customer-analytics'));
}

require_once BDFG_CA_PLUGIN_DIR . 'templates/admin-page.php';
}

/**
* 检查是否在插件页面
*/
private function is_plugin_page($hook) {
$plugin_pages = array(
'toplevel_page_bdfg-customer-analytics',
'bdfg-analytics_page_bdfg-customer-segments',
'bdfg-analytics_page_bdfg-analytics-settings'
);

return in_array($hook, $plugin_pages);
}

/**
* 注册插件设置
*/
public function register_settings() {
register_setting('bdfg_ca_settings', 'bdfg_ca_cache_enabled');
register_setting('bdfg_ca_settings', 'bdfg_ca_cache_duration', array(
'type' => 'integer',
'sanitize_callback' => array($this, 'sanitize_cache_duration')
));
}

/**
* 清理缓存时间设置
*/
public function sanitize_cache_duration($value) {
$value = intval($value);
return $value < 300 ? 300 : $value;
}

/**
* 添加插件链接
*/
public function add_plugin_links($links) {
$plugin_links = array(
'<a href="' . admin_url('admin.php?page=bdfg-customer-analytics') . '">' .
__('数据概览', 'bdfg-customer-analytics') . '</a>',
'<a href="' . admin_url('admin.php?page=bdfg-analytics-settings') . '">' .
__('设置', 'bdfg-customer-analytics') . '</a>'
);
return array_merge($plugin_links, $links);
}
}

includes/class-customer-charts.php

<?php
/**
* BDFG Customer Analytics 图表类
*
* @package BDFG_Customer_Analytics
* @since 2.0.0
* @author Bei Duo Feng Ou <[email protected]>
*/

defined('ABSPATH') || exit;

class BDFG_Customer_Charts {
/**
* 构造函数
*/
public function __construct() {
add_action('admin_enqueue_scripts', array($this, 'enqueue_chart_assets'));
add_action('wp_ajax_bdfg_get_chart_data', array($this, 'handle_ajax_chart_data'));
}

/**
* 加载图表所需资源
*/
public function enqueue_chart_assets($hook) {
if (!$this->is_bdfg_admin_page($hook)) {
return;
}

// 加载 Chart.js
wp_enqueue_script(
'bdfg-chartjs',
'https://cdn.jsdelivr.net/npm/[email protected]/dist/chart.min.js',
array(),
'3.7.0',
true
);

// 加载自定义图表脚本
wp_enqueue_script(
'bdfg-charts',
BDFG_CA_PLUGIN_URL . 'assets/js/charts.js',
array('jquery', 'bdfg-chartjs'),
BDFG_CA_VERSION,
true
);

// 本地化脚本
wp_localize_script('bdfg-charts', 'bdfgCharts', array(
'ajaxUrl' => admin_url('admin-ajax.php'),
'nonce' => wp_create_nonce('bdfg_charts_nonce'),
'i18n' => array(
'noData' => __('暂无数据', 'bdfg-customer-analytics'),
'loading' => __('加载中...', 'bdfg-customer-analytics'),
'error' => __('获取数据时发生错误', 'bdfg-customer-analytics')
)
));
}

/**
* 获取订单趋势数据
*/
public function get_order_trend_data($customer_id, $period) {
global $wpdb;

$cache_key = "bdfg_order_trend_{$customer_id}_{$period}";
$cached_data = wp_cache_get($cache_key);

if (false !== $cached_data) {
return $cached_data;
}

$date_from = date('Y-m-d', strtotime("-{$period} days"));

$query = $wpdb->prepare(
"SELECT
DATE(post_date) as order_date,
COUNT(*) as order_count,
SUM(pm.meta_value) as daily_total
FROM {$wpdb->posts} as posts
JOIN {$wpdb->postmeta} pm ON posts.ID = pm.post_id
WHERE posts.post_type = 'shop_order'
AND posts.post_status IN ('wc-completed', 'wc-processing')
AND pm.meta_key = '_order_total'
AND posts.post_author = %d
AND posts.post_date >= %s
GROUP BY DATE(post_date)
ORDER BY order_date ASC",
$customer_id,
$date_from
);

$results = $wpdb->get_results($query);

// 缓存结果
wp_cache_set($cache_key, $results, '', 3600);

return $results;
}

/**
* 获取产品分类数据
*/
public function get_product_categories_data($customer_id, $period = 30) {
global $wpdb;

$cache_key = "bdfg_product_cats_{$customer_id}_{$period}";
$cached_data = wp_cache_get($cache_key);

if (false !== $cached_data) {
return $cached_data;
}

$query = $wpdb->prepare(
"SELECT
terms.name as category,
COUNT(DISTINCT order_items.order_item_id) as item_count,
SUM(order_item_meta.meta_value) as category_total
FROM {$wpdb->prefix}woocommerce_order_items as order_items
JOIN {$wpdb->posts} as orders
ON order_items.order_id = orders.ID
JOIN {$wpdb->prefix}woocommerce_order_itemmeta as order_item_meta
ON order_items.order_item_id = order_item_meta.order_item_id
JOIN {$wpdb->term_relationships} as term_rels
ON order_item_meta.meta_value = term_rels.object_id
JOIN {$wpdb->term_taxonomy} as tax
ON term_rels.term_taxonomy_id = tax.term_taxonomy_id
JOIN {$wpdb->terms} as terms
ON tax.term_id = terms.term_id
WHERE orders.post_type = 'shop_order'
AND orders.post_status IN ('wc-completed', 'wc-processing')
AND orders.post_author = %d
AND orders.post_date >= %s
AND tax.taxonomy = 'product_cat'
AND order_item_meta.meta_key = '_product_id'
GROUP BY terms.term_id
ORDER BY item_count DESC
LIMIT 10",
$customer_id,
date('Y-m-d', strtotime("-{$period} days"))
);

$results = $wpdb->get_results($query);

// 缓存结果
wp_cache_set($cache_key, $results, '', 3600);

return $results;
}

/**
* 检查是否在BDFG分析页面
*/
private function is_bdfg_admin_page($hook) {
return in_array($hook, array(
'toplevel_page_bdfg-customer-analytics',
'bdfg-analytics_page_bdfg-customer-segments'
));
}
}

includes/class-customer-segments.php

相关文章: WooCommerce 自定义”加入购物车”按钮

<?php
/**
* BDFG Customer Analytics 客户分群类
*
* @package BDFG_Customer_Analytics
* @since 2.0.0
* @author Bei Duo Feng Ou <[email protected]>
*/

defined('ABSPATH') || exit;

class BDFG_Customer_Segments {
/**
* 数据库版本
*/
private $db_version = '1.0.1';

/**
* 构造函数
*/
public function __construct() {
add_action('admin_init', array($this, 'maybe_create_tables'));
add_action('wp_ajax_bdfg_save_segment', array($this, 'handle_save_segment'));
add_action('wp_ajax_bdfg_delete_segment', array($this, 'handle_delete_segment'));
}

/**
* 创建必要的数据表
*/
public function maybe_create_tables() {
if (get_option('bdfg_segments_db_version') === $this->db_version) {
return;
}

global $wpdb;
$charset_collate = $wpdb->get_charset_collate();

// 客户分群表
$segments_table = $wpdb->prefix . 'bdfg_customer_segments';
$sql = "CREATE TABLE IF NOT EXISTS $segments_table (
id bigint(20) NOT NULL AUTO_INCREMENT,
name varchar(255) NOT NULL,
description text,
conditions longtext,
created_by bigint(20) NOT NULL,
created_at datetime DEFAULT CURRENT_TIMESTAMP,
updated_at datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id),
KEY name (name),
KEY created_by (created_by)
) $charset_collate;";

// 客户标签表
$tags_table = $wpdb->prefix . 'bdfg_customer_tags';
$sql .= "CREATE TABLE IF NOT EXISTS $tags_table (
id bigint(20) NOT NULL AUTO_INCREMENT,
customer_id bigint(20) NOT NULL,
tag_name varchar(255) NOT NULL,
added_by bigint(20) NOT NULL,
added_at datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id),
KEY customer_id (customer_id),
KEY tag_name (tag_name),
KEY added_by (added_by)
) $charset_collate;";

require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
dbDelta($sql);

update_option('bdfg_segments_db_version', $this->db_version);
}

/**
* 添加新的客户分群
*/
public function add_segment($name, $description, $conditions) {
global $wpdb;

$result = $wpdb->insert(
$wpdb->prefix . 'bdfg_customer_segments',
array(
'name' => $name,
'description' => $description,
'conditions' => json_encode($conditions),
'created_by' => get_current_user_id()
),
array('%s', '%s', '%s', '%d')
);

return $result ? $wpdb->insert_id : false;
}

/**
* 获取分群中的客户
*/
public function get_segment_customers($segment_id) {
global $wpdb;

$segment = $wpdb->get_row($wpdb->prepare(
"SELECT * FROM {$wpdb->prefix}bdfg_customer_segments WHERE id = %d",
$segment_id
));

if (!$segment) {
return array();
}

$conditions = json_decode($segment->conditions, true);
return $this->apply_segment_conditions($conditions);
}

/**
* 应用分群条件获取客户列表
*/
private function apply_segment_conditions($conditions) {
global $wpdb;

$query = "SELECT DISTINCT
users.ID,
users.display_name,
users.user_email,
(SELECT COUNT(*) FROM {$wpdb->posts}
WHERE post_author = users.ID
AND post_type = 'shop_order'
AND post_status IN ('wc-completed', 'wc-processing')
) as order_count,
(SELECT SUM(meta_value) FROM {$wpdb->postmeta}
WHERE post_id IN (
SELECT ID FROM {$wpdb->posts}
WHERE post_author = users.ID
AND post_type = 'shop_order'
AND post_status IN ('wc-completed', 'wc-processing')
)
AND meta_key = '_order_total'
) as total_spent
FROM {$wpdb->users} as users
WHERE 1=1";

$where = array();
$query_args = array();

if (!empty($conditions['min_orders'])) {
$where[] = "order_count >= %d";
$query_args[] = $conditions['min_orders'];
}

if (!empty($conditions['min_spent'])) {
$where[] = "total_spent >= %f";
$query_args[] = $conditions['min_spent'];
}

if (!empty($where)) {
$query .= " HAVING " . implode(" AND ", $where);
}

$query .= " ORDER BY total_spent DESC";

return empty($query_args) ?
$wpdb->get_results($query) :
$wpdb->get_results($wpdb->prepare($query, $query_args));
}

/**
* 添加客户标签
*/
public function add_customer_tag($customer_id, $tag_name) {
global $wpdb;

return $wpdb->insert(
$wpdb->prefix . 'bdfg_customer_tags',
array(
'customer_id' => $customer_id,
'tag_name' => $tag_name,
'added_by' => get_current_user_id()
),
array('%d', '%s', '%d')
);
}

/**
* 获取客户的所有标签
*/
public function get_customer_tags($customer_id) {
global $wpdb;

return $wpdb->get_col($wpdb->prepare(
"SELECT DISTINCT tag_name
FROM {$wpdb->prefix}bdfg_customer_tags
WHERE customer_id = %d
ORDER BY added_at DESC",
$customer_id
));
}
}

includes/class-activator.php

<?php
/**
* BDFG Customer Analytics 激活器类
*
* @package BDFG_Customer_Analytics
* @since 2.0.0
* @author Bei Duo Feng Ou <[email protected]>
*/

defined('ABSPATH') || exit;

class BDFG_Customer_Analytics_Activator {
/**
* 激活插件时执行的操作
*/
public static function activate() {
// 检查PHP版本
if (version_compare(PHP_VERSION, BDFG_CA_MIN_PHP_VERSION, '<')) {
wp_die(
sprintf(
__('BDFG Customer Analytics 需要 PHP %s 或更高版本。', 'bdfg-customer-analytics'),
BDFG_CA_MIN_PHP_VERSION
),
__('插件激活错误', 'bdfg-customer-analytics'),
array('back_link' => true)
);
}

// 检查WordPress版本
if (version_compare(get_bloginfo('version'), BDFG_CA_MIN_WP_VERSION, '<')) {
wp_die(
sprintf(
__('BDFG Customer Analytics 需要 WordPress %s 或更高版本。', 'bdfg-customer-analytics'),
BDFG_CA_MIN_WP_VERSION
),
__('插件激活错误', 'bdfg-customer-analytics'),
array('back_link' => true)
);
}

// 检查WooCommerce
if (!class_exists('WooCommerce')) {
wp_die(
__('BDFG Customer Analytics 需要 WooCommerce 插件。请先安装并激活 WooCommerce。', 'bdfg-customer-analytics'),
__('插件激活错误', 'bdfg-customer-analytics'),
array('back_link' => true)
);
}

// 创建必要的数据表
self::create_tables();

// 设置默认选项
self::set_default_options();

// 创建缓存目录
self::create_cache_directory();

// 记录激活时间
update_option('bdfg_ca_activated_time', current_time('mysql'));
}

/**
* 创建必要的数据表
*/
private static function create_tables() {
if (!class_exists('BDFG_Customer_Segments')) {
require_once BDFG_CA_PLUGIN_DIR . 'includes/class-customer-segments.php';
}

$segments = new BDFG_Customer_Segments();
$segments->maybe_create_tables();
}

/**
* 设置默认选项
*/
private static function set_default_options() {
$defaults = array(
'report_period' => '30',
'cache_enabled' => '1',
'cache_duration' => '3600',
'chart_colors' => json_encode(array(
'#2271b1',
'#72aee6',
'#00a0d2',
'#04a4cc'
)),
'export_formats' => json_encode(array('csv', 'pdf')),
'analytics_email' => '',
'analytics_schedule' => 'weekly'
);

foreach ($defaults as $key => $value) {
if (false === get_option('bdfg_ca_' . $key)) {
update_option('bdfg_ca_' . $key, $value);
}
}
}

/**
* 创建缓存目录
*/
private static function create_cache_directory() {
$upload_dir = wp_upload_dir();
$cache_dir = $upload_dir['basedir'] . '/bdfg-analytics-cache';

if (!file_exists($cache_dir)) {
wp_mkdir_p($cache_dir);

// 创建 .htaccess 文件保护缓存目录
$htaccess_file = $cache_dir . '/.htaccess';
if (!file_exists($htaccess_file)) {
$htaccess_content = "deny from all\n";
file_put_contents($htaccess_file, $htaccess_content);
}

// 创建 index.php 文件
$index_file = $cache_dir . '/index.php';
if (!file_exists($index_file)) {
$index_content = "<?php\n// Silence is golden.";
file_put_contents($index_file, $index_content);
}
}
}
}

assets/css/admin.css

相关文章: Woocommerce强大的购物车管理扩展

/**
* BDFG Customer Analytics Admin Styles
*
* @package BDFG_Customer_Analytics
* @author Bei Duo Feng Ou <[email protected]>
* @version 1.0.1
*/

.bdfg-wrap {
margin: 20px 20px 0 0;
}

.bdfg-header {
background: #fff;
padding: 20px;
margin-bottom: 20px;
border: 1px solid #c3c4c7;
box-shadow: 0 1px 1px rgba(0,0,0,.04);
}

.bdfg-header h1 {
margin: 0;
font-size: 24px;
color: #1d2327;
}

.bdfg-nav-tab-wrapper {
margin-bottom: 20px;
border-bottom: 1px solid #c3c4c7;
}

.bdfg-card {
background: #fff;
border: 1px solid #c3c4c7;
box-shadow: 0 1px 1px rgba(0,0,0,.04);
margin-bottom: 20px;
padding: 20px;
}

.bdfg-card h2 {
margin-top: 0;
font-size: 18px;
border-bottom: 1px solid #eee;
padding-bottom: 12px;
}

.bdfg-chart-container {
min-height: 400px;
position: relative;
margin-bottom: 30px;
}

.bdfg-loading {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
text-align: center;
}

.bdfg-loading::after {
content: "";
display: block;
width: 40px;
height: 40px;
border: 4px solid #2271b1;
border-top-color: transparent;
border-radius: 50%;
animation: bdfg-spin 1s linear infinite;
}

.bdfg-segments-table {
width: 100%;
border-collapse: collapse;
margin-top: 15px;
}

.bdfg-segments-table th,
.bdfg-segments-table td {
padding: 12px;
text-align: left;
border-bottom: 1px solid #eee;
}

.bdfg-segments-table th {
background: #f8f9fa;
font-weight: 600;
}

.bdfg-tag {
display: inline-block;
padding: 4px 8px;
background: #e9ecef;
border-radius: 3px;
margin: 2px;
font-size: 12px;
}

.bdfg-button {
display: inline-block;
padding: 8px 16px;
background: #2271b1;
color: #fff;
border: none;
border-radius: 3px;
cursor: pointer;
text-decoration: none;
font-size: 14px;
}

.bdfg-button:hover {
background: #135e96;
color: #fff;
}

.bdfg-button.secondary {
background: #f0f0f1;
color: #2c3338;
}

.bdfg-button.secondary:hover {
background: #e0e0e0;
color: #2c3338;
}

@keyframes bdfg-spin {
to {
transform: rotate(360deg);
}
}

/* 响应式布局 */
@media screen and (max-width: 782px) {
.bdfg-card {
padding: 15px;
}

.bdfg-chart-container {
min-height: 300px;
}

.bdfg-segments-table th,
.bdfg-segments-table td {
padding: 8px;
}
}

assets/js/admin.js

/**
* BDFG Customer Analytics Admin Scripts
*
* @package BDFG_Customer_Analytics
* @author Bei Duo Feng Ou <[email protected]>
* @version 1.0.1
*/

(function($) {
'use strict';

// 主要对象
const BDFG_Admin = {
init: function() {
this.initDatePickers();
this.initTabs();
this.initSegments();
this.initExport();
this.initRefreshData();
},

// 初始化日期选择器
initDatePickers: function() {
$('.bdfg-date-picker').datepicker({
dateFormat: 'yy-mm-dd',
maxDate: '0',
onSelect: function(dateText) {
BDFG_Admin.refreshData();
}
});
},

// 初始化标签页
initTabs: function() {
$('.bdfg-nav-tab').on('click', function(e) {
e.preventDefault();

const $this = $(this);
const tabId = $this.data('tab');

// 更新活动标签
$('.bdfg-nav-tab').removeClass('nav-tab-active');
$this.addClass('nav-tab-active');

// 显示对应内容
$('.bdfg-tab-content').hide();
$('#' + tabId).show();

// 更新URL
if (history.pushState) {
const newUrl = window.location.protocol + "//" + window.location.host + window.location.pathname + '?page=bdfg-customer-analytics&tab=' + tabId;
window.history.pushState({path: newUrl}, '', newUrl);
}
});
},

// 初始化客户分群功能
initSegments: function() {
// 保存分群
$('#bdfg-save-segment').on('click', function(e) {
e.preventDefault();

const data = {
action: 'bdfg_save_segment',
nonce: bdfgCA.nonce,
name: $('#segment-name').val(),
description: $('#segment-description').val(),
conditions: BDFG_Admin.getSegmentConditions()
};

$.post(bdfgCA.ajaxUrl, data, function(response) {
if (response.success) {
BDFG_Admin.showNotice('分群保存成功', 'success');
BDFG_Admin.refreshSegmentsList();
} else {
BDFG_Admin.showNotice('保存失败: ' + response.data, 'error');
}
});
});

// 删除分群
$(document).on('click', '.bdfg-delete-segment', function(e) {
e.preventDefault();

if (!confirm('确定要删除这个分群吗?此操作不可恢复。')) {
return;
}

const segmentId = $(this).data('id');
const data = {
action: 'bdfg_delete_segment',
nonce: bdfgCA.nonce,
segment_id: segmentId
};

$.post(bdfgCA.ajaxUrl, data, function(response) {
if (response.success) {
BDFG_Admin.showNotice('分群已删除', 'success');
BDFG_Admin.refreshSegmentsList();
} else {
BDFG_Admin.showNotice('删除失败: ' + response.data, 'error');
}
});
});
},

// 初始化导出功能
initExport: function() {
$('#bdfg-export-data').on('click', function(e) {
e.preventDefault();

const format = $('#export-format').val();
const period = $('#report-period').val();

const data = {
action: 'bdfg_export_analytics',
nonce: bdfgCA.nonce,
format: format,
period: period
};

$.post(bdfgCA.ajaxUrl, data, function(response) {
if (response.success) {
window.location.href = response.data.download_url;
} else {
BDFG_Admin.showNotice('导出失败: ' + response.data, 'error');
}
});
});
},

// 刷新数据
refreshData: function() {
$('.bdfg-chart-container').each(function() {
const $container = $(this);
const chartType = $container.data('chart');

$container.addClass('loading');

const data = {
action: 'bdfg_get_customer_analytics',
nonce: bdfgCA.nonce,
chart: chartType,
period: $('#report-period').val()
};

$.post(bdfgCA.ajaxUrl, data, function(response) {
$container.removeClass('loading');

if (response.success) {
BDFG_Charts.updateChart(chartType, response.data);
} else {
BDFG_Admin.showNotice('获取数据失败: ' + response.data, 'error');
}
});
});
},

// 获取分群条件
getSegmentConditions: function() {
return {
min_orders: parseInt($('#condition-min-orders').val()) || 0,
min_spent: parseFloat($('#condition-min-spent').val()) || 0,
registration_date: $('#condition-registration-date').val(),
last_order_date: $('#condition-last-order-date').val()
};
},

// 显示通知
showNotice: function(message, type) {
const $notice = $('<div>')
.addClass('notice notice-' + type)
.append($('<p>').text(message));

$('.bdfg-notices').html($notice);

setTimeout(function() {
$notice.fadeOut(function() {
$(this).remove();
});
}, 3000);
}
};

// 初始化
$(document).ready(function() {
BDFG_Admin.init();
});

})(jQuery);

assets/js/charts.js

相关文章: WooCommerce 快速下单插件

/**
* BDFG Customer Analytics Charts Scripts
*
* @package BDFG_Customer_Analytics
* @author Bei Duo Feng Ou <[email protected]>
* @version 1.0.1
*/

const BDFG_Charts = {
charts: {},
colors: [
'#2271b1',
'#72aee6',
'#00a0d2',
'#04a4cc'
],

init: function() {
// 设置Chart.js默认配置
Chart.defaults.font.family = '-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif';
Chart.defaults.color = '#50575e';

this.initOrdersChart();
this.initCategoriesChart();
this.initSpendingChart();
},

initOrdersChart: function() {
const ctx = document.getElementById('bdfg-orders-chart');
if (!ctx) return;

this.charts.orders = new Chart(ctx, {
type: 'line',
data: {
labels: [],
datasets: [{
label: '订单数量',
data: [],
borderColor: this.colors[0],
backgroundColor: this.colors[0] + '20',
tension: 0.4,
fill: true
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
position: 'top'
},
tooltip: {
mode: 'index',
intersect: false
}
},
scales: {
y: {
beginAtZero: true,
ticks: {
precision: 0
}
}
}
}
});
},

initCategoriesChart: function() {
const ctx = document.getElementById('bdfg-categories-chart');
if (!ctx) return;

this.charts.categories = new Chart(ctx, {
type: 'doughnut',
data: {
labels: [],
datasets: [{
data: [],
backgroundColor: this.colors,
borderColor: '#fff',
borderWidth: 2
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
position: 'right'
},
tooltip: {
callbacks: {
label: function(context) {
const label = context.label || '';
const value = context.parsed || 0;
const total = context.dataset.data.reduce((a, b) => a + b);
const percentage = total ? Math.round((value / total) * 100) : 0;
return `${label}: ${value} (${percentage}%)`;
}
}
}
}
}
});
},

initSpendingChart: function() {
const ctx = document.getElementById('bdfg-spending-chart');
if (!ctx) return;

this.charts.spending = new Chart(ctx, {
type: 'bar',
data: {
labels: [],
datasets: [{
label: '消费金额',
data: [],
backgroundColor: this.colors[1],
borderColor: this.colors[1],
borderWidth: 1
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
display: false
},
tooltip: {
callbacks: {
label: function(context) {
return '¥' + context.parsed.y.toFixed(2);
}
}
}
},
scales: {
y: {
beginAtZero: true,
ticks: {
callback: function(value) {
return '¥' + value;
}
}
}
}
}
});
},

updateChart: function(chartType, data) {
if (!this.charts[chartType]) return;

const chart = this.charts[chartType];

switch (chartType) {
case 'orders':
chart.data.labels = data.dates;
chart.data.datasets[0].data = data.orders;
break;

case 'categories':
chart.data.labels = data.categories;
chart.data.datasets[0].data = data.counts;
break;

case 'spending':
chart.data.labels = data.dates;
chart.data.datasets[0].data = data.amounts;
break;
}

chart.update();
},

destroy: function() {
Object.values(this.charts).forEach(chart => {
if (chart) {
chart.destroy();
}
});
this.charts = {};
}
};

// 页面加载完成后初始化图表
document.addEventListener('DOMContentLoaded', function() {
BDFG_Charts.init();
});

templates/admin-page.php

<?php
/**
* BDFG Customer Analytics 管理页面模板
*
* @package BDFG_Customer_Analytics
* @version 1.0.1
*/

defined('ABSPATH') || exit;

// 获取当前标签页
$current_tab = isset($_GET['tab']) ? sanitize_key($_GET['tab']) : 'dashboard';
?>

<div class="wrap bdfg-wrap">
<div class="bdfg-header">
<h1><?php _e('BDFG 客户分析', 'bdfg-customer-analytics'); ?></h1>
</div>

<div class="bdfg-notices"></div>

<nav class="nav-tab-wrapper bdfg-nav-tab-wrapper">
<a href="#" class="nav-tab <?php echo $current_tab === 'dashboard' ? 'nav-tab-active' : ''; ?>"
data-tab="bdfg-dashboard">
<?php _e('数据概览', 'bdfg-customer-analytics'); ?>
</a>
<a href="#" class="nav-tab <?php echo $current_tab === 'segments' ? 'nav-tab-active' : ''; ?>"
data-tab="bdfg-segments">
<?php _e('客户分群', 'bdfg-customer-analytics'); ?>
</a>
<a href="#" class="nav-tab <?php echo $current_tab === 'settings' ? 'nav-tab-active' : ''; ?>"
data-tab="bdfg-settings">
<?php _e('设置', 'bdfg-customer-analytics'); ?>
</a>
</nav>

<!-- 数据概览面板 -->
<div id="bdfg-dashboard" class="bdfg-tab-content" <?php echo $current_tab !== 'dashboard' ? 'style="display:none;"' : ''; ?>>
<div class="bdfg-card">
<div class="bdfg-card-header">
<select id="report-period" class="bdfg-select">
<option value="7"><?php _e('最近7天', 'bdfg-customer-analytics'); ?></option>
<option value="30" selected><?php _e('最近30天', 'bdfg-customer-analytics'); ?></option>
<option value="90"><?php _e('最近90天', 'bdfg-customer-analytics'); ?></option>
<option value="365"><?php _e('最近一年', 'bdfg-customer-analytics'); ?></option>
</select>

<button id="bdfg-export-data" class="bdfg-button">
<?php _e('导出数据', 'bdfg-customer-analytics'); ?>
</button>
</div>

<div class="bdfg-stats-grid">
<div class="bdfg-stat-card">
<h3><?php _e('总订单数', 'bdfg-customer-analytics'); ?></h3>
<div class="bdfg-stat-value" id="total-orders">--</div>
</div>

<div class="bdfg-stat-card">
<h3><?php _e('总销售额', 'bdfg-customer-analytics'); ?></h3>
<div class="bdfg-stat-value" id="total-revenue">--</div>
</div>

<div class="bdfg-stat-card">
<h3><?php _e('平均订单金额', 'bdfg-customer-analytics'); ?></h3>
<div class="bdfg-stat-value" id="avg-order-value">--</div>
</div>
</div>

<div class="bdfg-chart-container" data-chart="orders">
<canvas id="bdfg-orders-chart"></canvas>
</div>
</div>

<div class="bdfg-card">
<h2><?php _e('商品类别分析', 'bdfg-customer-analytics'); ?></h2>
<div class="bdfg-chart-container" data-chart="categories">
<canvas id="bdfg-categories-chart"></canvas>
</div>
</div>
</div>

<!-- 客户分群面板 -->
<div id="bdfg-segments" class="bdfg-tab-content" <?php echo $current_tab !== 'segments' ? 'style="display:none;"' : ''; ?>>
<div class="bdfg-card">
<h2><?php _e('创建新分群', 'bdfg-customer-analytics'); ?></h2>

<div class="bdfg-form-group">
<label for="segment-name"><?php _e('分群名称', 'bdfg-customer-analytics'); ?></label>
<input type="text" id="segment-name" class="regular-text">
</div>

<div class="bdfg-form-group">
<label for="segment-description"><?php _e('分群描述', 'bdfg-customer-analytics'); ?></label>
<textarea id="segment-description" class="large-text" rows="3"></textarea>
</div>

<div class="bdfg-form-group">
<h3><?php _e('分群条件', 'bdfg-customer-analytics'); ?></h3>

<div class="bdfg-condition-row">
<label for="condition-min-orders"><?php _e('最少订单数', 'bdfg-customer-analytics'); ?></label>
<input type="number" id="condition-min-orders" min="0">
</div>

<div class="bdfg-condition-row">
<label for="condition-min-spent"><?php _e('最低消费金额', 'bdfg-customer-analytics'); ?></label>
<input type="number" id="condition-min-spent" min="0" step="0.01">
</div>
</div>

<button id="bdfg-save-segment" class="bdfg-button">
<?php _e('保存分群', 'bdfg-customer-analytics'); ?>
</button>
</div>

<div class="bdfg-card">
<h2><?php _e('现有分群', 'bdfg-customer-analytics'); ?></h2>
<div id="bdfg-segments-list">
<!-- 分群列表将通过AJAX加载 -->
</div>
</div>
</div>

<!-- 设置面板 -->
<div id="bdfg-settings" class="bdfg-tab-content" <?php echo $current_tab !== 'settings' ? 'style="display:none;"' : ''; ?>>
<div class="bdfg-card">
<h2><?php _e('常规设置', 'bdfg-customer-analytics'); ?></h2>
<form method="post" action="options.php">
<?php
settings_fields('bdfg_ca_settings');
do_settings_sections('bdfg_ca_settings');
?>
<table class="form-table">
<tr>
<th scope="row">
<label for="bdfg_ca_cache_enabled">
<?php _e('启用缓存', 'bdfg-customer-analytics'); ?>
</label>
</th>
<td>
<input type="checkbox" id="bdfg_ca_cache_enabled"
name="bdfg_ca_cache_enabled" value="1"
<?php checked(get_option('bdfg_ca_cache_enabled'), '1'); ?>>
<p class="description">
<?php _e('启用数据缓存以提升性能', 'bdfg-customer-analytics'); ?>
</p>
</td>
</tr>

<tr>
<th scope="row">
<label for="bdfg_ca_cache_duration">
<?php _e('缓存时间', 'bdfg-customer-analytics'); ?>
</label>
</th>
<td>
<input type="number" id="bdfg_ca_cache_duration"
name="bdfg_ca_cache_duration"
value="<?php echo esc_attr(get_option('bdfg_ca_cache_duration', '3600')); ?>"
min="300" step="300">
<p class="description">
<?php _e('缓存有效期(秒)', 'bdfg-customer-analytics'); ?>
</p>
</td>
</tr>
</table>

<?php submit_button(__('保存设置', 'bdfg-customer-analytics')); ?>
</form>
</div>
</div>
</div>

languages/bdfg-customer-analytics-zh_CN.po

msgid ""
msgstr ""
"Project-Id-Version: BDFG Customer Analytics for WooCommerce 1.0.1\n"
"Report-Msgid-Bugs-To: https://beiduofengou.net/support\n"
"POT-Creation-Date: 2024-05-15 11:54:58+00:00\n"
"PO-Revision-Date: 2024-05-15 11:54:58+00:00\n"
"Last-Translator: Bei Duo Feng Ou <[email protected]>\n"
"Language-Team: LANGUAGE <[email protected]>\n"
"Language: zh_CN\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
"X-Generator: Bei Duo Feng Ou\n"
"X-Domain: bdfg-customer-analytics\n"

#: includes/class-customer-analytics.php:123
msgid "BDFG 客户分析"
msgstr ""

#: includes/class-customer-analytics.php:124
msgid "BDFG 分析"
msgstr ""

#: templates/admin-page.php:42
msgid "数据概览"
msgstr ""

#: templates/admin-page.php:46
msgid "客户分群"
msgstr ""

#: templates/admin-page.php:50
msgid "设置"
msgstr ""

#: templates/admin-page.php:63
msgid "最近7天"
msgstr ""

#: templates/admin-page.php:64
msgid "最近30天"
msgstr ""

#: templates/admin-page.php:65
msgid "最近90天"
msgstr ""

#: templates/admin-page.php:66
msgid "最近一年"
msgstr ""

#: templates/admin-page.php:71
msgid "导出数据"
msgstr ""

#: templates/admin-page.php:78
msgid "总订单数"
msgstr ""

#: templates/admin-page.php:83
msgid "总销售额"
msgstr ""

#: templates/admin-page.php:88
msgid "平均订单金额"
msgstr ""

#: templates/admin-page.php:99
msgid "商品类别分析"
msgstr ""

#: templates/admin-page.php:109
msgid "创建新分群"
msgstr ""

#: templates/admin-page.php:113
msgid "分群名称"
msgstr ""

#: templates/admin-page.php:118
msgid "分群描述"
msgstr ""

#: templates/admin-page.php:123
msgid "分群条件"
msgstr ""

#: templates/admin-page.php:127
msgid "最少订单数"
msgstr ""

#: templates/admin-page.php:132
msgid "最低消费金额"
msgstr ""

#: templates/admin-page.php:139
msgid "保存分群"
msgstr ""

#: templates/admin-page.php:144
msgid "现有分群"
msgstr ""

#: templates/admin-page.php:155
msgid "常规设置"
msgstr ""

#: templates/admin-page.php:164
msgid "启用缓存"
msgstr ""

#: templates/admin-page.php:171
msgid "启用数据缓存以提升性能"
msgstr ""

#: templates/admin-page.php:178
msgid "缓存时间"
msgstr ""

#: templates/admin-page.php:187
msgid "缓存有效期(秒)"
msgstr ""

#: templates/admin-page.php:192
msgid "保存设置"
msgstr ""

Leave a Comment