为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 ""