是一款强大的 WooCommerce 折扣插件,它允许您为不同的用户角色设置不同的折扣规则,满足各种定价策略需求。
### 主要功能
* **基于用户角色的折扣**: 为不同用户角色设置不同折扣
* **多种折扣类型**: 支持百分比折扣和固定金额折扣
* **产品分类限制**: 可将折扣限制在特定产品分类
* **时间限制**: 设置折扣的开始和结束日期
* **首次购买限制**: 可设置折扣仅适用于用户的首次购买
* **最低订单金额**: 设置应用折扣所需的最低订单金额
* **附加条件**: 支持多种条件组合,如星期几、一天中的时间、客户订单数量和消费金额等
* **排除项设置**: 可排除特定产品、用户或已有特价产品
* **优化的用户界面**: 直观的后台设置界面,拖拽排序规则
* **折扣测试工具**: 方便测试和调试折扣规则
* **导入/导出**: 支持折扣规则的导入和导出
* **缓存支持**: 与页面缓存插件兼容
* **多货币支持**: 与主流多货币插件兼容
相关文章: WooCommerce 页脚增强器
<?php /** * Plugin Name: BDFG Role-Based Discounts for WooCommerce * Plugin URI:https://beiduofengou.net/2025/01/28/bdfg-role-discounts/ * Description: 全功能用户角色折扣系统,支持按角色设置百分比折扣、固定金额折扣、最低订单金额、产品类别折扣、限时折扣等。 * Version: 2.6.0 * Author: Bei Duo Feng Ou * Author URI: https://beiduofengou.net * Text Domain: bdfg-role-discounts * Domain Path: /languages * Requires at least: 5.6 * Requires PHP: 7.3 * WC requires at least: 5.0 * WC tested up to: 7.8 * License: GPL v2 or later * License URI: https://www.gnu.org/licenses/gpl-2.0.html */ // 如果直接访问此文件,则中止执行 if (!defined('ABSPATH')) { exit; } if (!class_exists('BDFG_Role_Discounts')) { /** * BDFG角色折扣插件主类 * * @since 1.0.0 */ class BDFG_Role_Discounts { // 单例模式实例 private static $instance = null; // 插件版本 private $version = '2.6.0'; // 插件设置 private $settings; // 插件选项名称 private $option_name = 'bdfg_role_discounts_settings'; // 用户首次购买记录选项名称 private $first_purchase_option = 'bdfg_user_first_purchases'; // 插件路径和URL private $plugin_path; private $plugin_url; /** * 主要构造函数 */ private function __construct() { // 设置插件路径和URL $this->plugin_path = plugin_dir_path(__FILE__); $this->plugin_url = plugin_dir_url(__FILE__); // 加载文本域用于翻译 add_action('plugins_loaded', array($this, 'load_plugin_textdomain')); // 检查 WooCommerce 是否激活 add_action('admin_init', array($this, 'check_woocommerce_active')); // 注册设置页面 add_action('admin_menu', array($this, 'add_admin_menu')); add_action('admin_init', array($this, 'register_settings')); // 添加设置链接到插件页面 add_filter('plugin_action_links_' . plugin_basename(__FILE__), array($this, 'add_settings_link')); // 加载设置 $this->settings = get_option($this->option_name, array()); // 应用折扣 add_action('woocommerce_before_calculate_totals', array($this, 'apply_discounts'), 99); // 处理订单完成后的任务 add_action('woocommerce_order_status_completed', array($this, 'process_completed_order')); // 显示折扣信息 add_action('woocommerce_before_add_to_cart_form', array($this, 'display_discount_info')); // 显示原价 add_filter('woocommerce_get_price_html', array($this, 'show_original_price'), 99, 2); // 加载CSS和JS add_action('admin_enqueue_scripts', array($this, 'enqueue_admin_scripts')); add_action('wp_enqueue_scripts', array($this, 'enqueue_frontend_scripts')); // Ajax 处理 add_action('wp_ajax_bdfg_test_discount_rule', array($this, 'ajax_test_discount_rule')); add_action('wp_ajax_bdfg_export_settings', array($this, 'ajax_export_settings')); add_action('wp_ajax_bdfg_import_settings', array($this, 'ajax_import_settings')); add_action('wp_ajax_bdfg_reset_first_purchase', array($this, 'ajax_reset_first_purchase')); // 产品选择器的Ajax add_action('wp_ajax_bdfg_search_products', array($this, 'ajax_search_products')); add_action('wp_ajax_bdfg_search_users', array($this, 'ajax_search_users')); } /** * 获取单例实例 * * @since 1.0.0 * @return BDFG_Role_Discounts */ public static function get_instance() { if (null === self::$instance) { self::$instance = new self(); } return self::$instance; } /** * 获取插件路径 * * @since 2.0.0 * @return string */ public function get_plugin_path() { return $this->plugin_path; } /** * 获取插件URL * * @since 2.0.0 * @return string */ public function get_plugin_url() { return $this->plugin_url; } /** * 加载插件文本域 * * @since 1.0.0 */ public function load_plugin_textdomain() { load_plugin_textdomain('bdfg-role-discounts', false, dirname(plugin_basename(__FILE__)) . '/languages'); } /** * 检查 WooCommerce 是否激活 * * @since 1.0.0 */ public function check_woocommerce_active() { if (!class_exists('WooCommerce')) { add_action('admin_notices', array($this, 'woocommerce_missing_notice')); deactivate_plugins(plugin_basename(__FILE__)); if (isset($_GET['activate'])) { unset($_GET['activate']); } } } /** * WooCommerce 缺失提示 * * @since 1.0.0 */ public function woocommerce_missing_notice() { ?> <div class="error"> <p><?php _e('BDFG Role-Based Discounts 需要 WooCommerce 插件。请安装并激活 WooCommerce 后再试。', 'bdfg-role-discounts'); ?></p> </div> <?php } /** * 添加管理菜单 * * @since 1.0.0 */ public function add_admin_menu() { add_submenu_page( 'woocommerce', __('BDFG Role Discounts', 'bdfg-role-discounts'), __('Role Discounts', 'bdfg-role-discounts'), 'manage_woocommerce', 'bdfg-role-discounts', array($this, 'admin_page') ); } /** * 注册设置 * * @since 1.0.0 */ public function register_settings() { register_setting( 'bdfg_role_discounts_group', $this->option_name, array($this, 'sanitize_settings') ); } /** * 添加设置链接 * * @since 1.0.0 * @param array $links 插件操作链接 * @return array */ public function add_settings_link($links) { $settings_link = '<a href="admin.php?page=bdfg-role-discounts">' . __('设置', 'bdfg-role-discounts') . '</a>'; array_unshift($links, $settings_link); return $links; } /** * 加载管理页面的CSS和JS * * @since 1.0.0 * @param string $hook 当前页面的钩子后缀 */ public function enqueue_admin_scripts($hook) { if ('woocommerce_page_bdfg-role-discounts' !== $hook) { return; } // 管理页面CSS wp_enqueue_style('bdfg-admin-style', $this->plugin_url . 'assets/css/admin.css', array(), $this->version); // Select2 wp_enqueue_style('select2', $this->plugin_url . 'assets/css/select2.min.css', array(), '4.1.0'); wp_enqueue_script('select2', $this->plugin_url . 'assets/js/select2.min.js', array('jquery'), '4.1.0', true); // 日期选择器 wp_enqueue_script('jquery-ui-datepicker'); wp_enqueue_script('jquery-ui-sortable'); wp_enqueue_style('jquery-ui-style', '//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css'); // 管理页面JS wp_enqueue_script('bdfg-admin-script', $this->plugin_url . 'assets/js/admin.js', array('jquery', 'jquery-ui-datepicker', 'jquery-ui-sortable', 'select2'), $this->version, true); // 本地化脚本 wp_localize_script('bdfg-admin-script', 'bdfg_params', array( 'ajax_url' => admin_url('admin-ajax.php'), 'nonce' => wp_create_nonce('bdfg-admin-nonce'), 'currency_symbol' => get_woocommerce_currency_symbol(), 'date_format' => _x('mm/dd/yy', 'jQuery datepicker date format', 'bdfg-role-discounts'), 'i18n' => array( 'confirm_delete' => __('确定要删除此规则吗?此操作无法撤销。', 'bdfg-role-discounts'), 'confirm_reset' => __('确定要重置所有用户的首次购买记录吗?此操作无法撤销。', 'bdfg-role-discounts'), 'confirm_import' => __('导入设置将覆盖当前所有配置,确定要继续吗?', 'bdfg-role-discounts'), 'copied' => __('已复制到剪贴板', 'bdfg-role-discounts'), 'copy_failed' => __('复制失败,请手动复制', 'bdfg-role-discounts'), 'rule_updated' => __('规则已更新', 'bdfg-role-discounts'), 'import_success' => __('设置导入成功', 'bdfg-role-discounts'), 'import_error' => __('导入失败,请检查设置格式', 'bdfg-role-discounts'), 'reset_success' => __('首次购买记录已重置', 'bdfg-role-discounts'), 'search_products' => __('搜索产品...', 'bdfg-role-discounts'), 'search_users' => __('搜索用户...', 'bdfg-role-discounts') ) )); } /** * 加载前端脚本和样式 * * @since 2.0.0 */ public function enqueue_frontend_scripts() { // 只在产品页面加载 if (is_product() && (!empty($this->settings['show_discount_info']) || !empty($this->settings['show_original_price']))) { wp_enqueue_style('bdfg-frontend-style', $this->plugin_url . 'assets/css/frontend.css', array(), $this->version); } } /** * 渲染管理页面 * * @since 1.0.0 */ public function admin_page() { // 检查用户权限 if (!current_user_can('manage_woocommerce')) { wp_die(__('您没有足够的权限访问此页面', 'bdfg-role-discounts')); } // 获取所有用户角色 $roles = $this->get_all_user_roles(); // 获取所有产品分类 $product_categories = get_terms(array( 'taxonomy' => 'product_cat', 'hide_empty' => false, )); // 获取多货币支持 $currencies = $this->get_available_currencies(); ?> <div class="wrap bdfg-role-discounts"> <h1><?php _e('BDFG 用户角色折扣设置', 'bdfg-role-discounts'); ?></h1> <div class="bdfg-header-banner"> <span class="bdfg-version"><?php printf(__('版本: %s', 'bdfg-role-discounts'), $this->version); ?></span> <a href="https://beiduofengou.net/plugins/bdfg-role-discounts/docs" target="_blank" class="bdfg-docs-link"><?php _e('文档', 'bdfg-role-discounts'); ?></a> <a href="https://beiduofengou.net/support" target="_blank" class="bdfg-support-link"><?php _e('支持', 'bdfg-role-discounts'); ?></a> </div> <form method="post" action="options.php" id="bdfg-discount-form"> <?php settings_fields('bdfg_role_discounts_group'); ?> <div class="bdfg-tabs"> <ul class="bdfg-tabs-nav"> <li class="active"><a href="#discount-rules"><?php _e('折扣规则', 'bdfg-role-discounts'); ?></a></li> <li><a href="#excluded-items"><?php _e('排除项', 'bdfg-role-discounts'); ?></a></li> <li><a href="#settings"><?php _e('常规设置', 'bdfg-role-discounts'); ?></a></li> <li><a href="#tools"><?php _e('工具', 'bdfg-role-discounts'); ?></a></li> </ul> <div class="bdfg-tab-content"> <!-- 折扣规则面板 --> <div id="discount-rules" class="bdfg-tab-pane active"> <h2><?php _e('折扣规则', 'bdfg-role-discounts'); ?> <button type="button" class="button button-secondary add-rule"><?php _e('添加规则', 'bdfg-role-discounts'); ?></button> </h2> <div class="bdfg-rules-container"> <?php if (!empty($this->settings['rules']) && is_array($this->settings['rules'])) { foreach ($this->settings['rules'] as $rule_id => $rule) { $this->render_rule_row($rule_id, $rule, $roles, $product_categories, $currencies); } } ?> <!-- 规则模板 - 用于JavaScript克隆 --> <div class="bdfg-rule-row rule-template" style="display: none;"> <?php $this->render_rule_row('RULE_ID', array(), $roles, $product_categories, $currencies); ?> </div> </div> </div> <!-- 排除项面板 --> <div id="excluded-items" class="bdfg-tab-pane"> <h2><?php _e('排除项设置', 'bdfg-role-discounts'); ?></h2> <table class="form-table"> <tr> <th scope="row"><?php _e('排除的产品', 'bdfg-role-discounts'); ?></th> <td> <select name="<?php echo esc_attr($this->option_name); ?>[excluded_products][]" class="bdfg-product-select" multiple="multiple" style="width: 100%;"> <?php if (!empty($this->settings['excluded_products'])) { foreach ($this->settings['excluded_products'] as $product_id) { $product = wc_get_product($product_id); if ($product) { echo '<option value="' . esc_attr($product_id) . '" selected>' . esc_html($product->get_name()) . ' (#' . $product_id . ')</option>'; } } } ?> </select> <p class="description"><?php _e('这些产品不会应用任何折扣规则', 'bdfg-role-discounts'); ?></p> </td> </tr> <tr> <th scope="row"><?php _e('排除的用户', 'bdfg-role-discounts'); ?></th> <td> <select name="<?php echo esc_attr($this->option_name); ?>[excluded_users][]" class="bdfg-user-select" multiple="multiple" style="width: 100%;"> <?php if (!empty($this->settings['excluded_users'])) { foreach ($this->settings['excluded_users'] as $user_id) { $user = get_userdata($user_id); if ($user) { echo '<option value="' . esc_attr($user_id) . '" selected>' . esc_html($user->display_name) . ' (' . $user->user_email . ')</option>'; } } } ?> </select> <p class="description"><?php _e('这些用户不会获得任何折扣', 'bdfg-role-discounts'); ?></p> </td> </tr> <tr> <th scope="row"><?php _e('排除特价产品', 'bdfg-role-discounts'); ?></th> <td> <label> <input type="checkbox" name="<?php echo esc_attr($this->option_name); ?>[exclude_sale_items]" value="1" <?php checked(!empty($this->settings['exclude_sale_items'])); ?> /> <?php _e('排除已有特价的产品', 'bdfg-role-discounts'); ?> </label> <p class="description"><?php _e('WooCommerce 中已标记为特价的产品将不会应用角色折扣', 'bdfg-role-discounts'); ?></p> </td> </tr> </table> </div> <!-- 常规设置面板 --> <div id="settings" class="bdfg-tab-pane"> <h2><?php _e('常规设置', 'bdfg-role-discounts'); ?></h2> <table class="form-table"> <tr> <th scope="row"><?php _e('显示原价', 'bdfg-role-discounts'); ?></th> <td> <label> <input type="checkbox" name="<?php echo esc_attr($this->option_name); ?>[show_original_price]" value="1" <?php checked(!empty($this->settings['show_original_price'])); ?> /> <?php _e('在折扣价格旁显示划线的原价', 'bdfg-role-discounts'); ?> </label> </td> </tr> <tr> <th scope="row"><?php _e('显示折扣信息', 'bdfg-role-discounts'); ?></th> <td> <label> <input type="checkbox" name="<?php echo esc_attr($this->option_name); ?>[show_discount_info]" value="1" <?php checked(!empty($this->settings['show_discount_info'])); ?> /> <?php _e('在产品页面显示用户折扣信息', 'bdfg-role-discounts'); ?> </label> </td> </tr> <tr> <th scope="row"><?php _e('折扣信息文本', 'bdfg-role-discounts'); ?></th> <td> <input type="text" name="<?php echo esc_attr($this->option_name); ?>[discount_text]" value="<?php echo esc_attr(!empty($this->settings['discount_text']) ? $this->settings['discount_text'] : __('您享有 {discount} 的折扣!', 'bdfg-role-discounts')); ?>" class="regular-text" /> <p class="description"><?php _e('可使用的变量: {discount}, {role}', 'bdfg-role-discounts'); ?></p> </td> </tr> <tr> <th scope="row"><?php _e('缓存支持', 'bdfg-role-discounts'); ?></th> <td> <label> <input type="checkbox" name="<?php echo esc_attr($this->option_name); ?>[enable_cache_support]" value="1" <?php checked(!empty($this->settings['enable_cache_support'])); ?> /> <?php _e('启用与页面缓存插件的兼容性', 'bdfg-role-discounts'); ?> </label> <p class="description"><?php _e('如果您使用页面缓存插件(如WP Super Cache、W3 Total Cache等),请启用此选项以确保折扣正常显示', 'bdfg-role-discounts'); ?></p> </td> </tr> <tr> <th scope="row"><?php _e('性能优化', 'bdfg-role-discounts'); ?></th> <td> <label> <input type="checkbox" name="<?php echo esc_attr($this->option_name); ?>[enable_performance_mode]" value="1" <?php checked(!empty($this->settings['enable_performance_mode'])); ?> /> <?php _e('启用性能优化模式', 'bdfg-role-discounts'); ?> </label> <p class="description"><?php _e('减少数据库查询和优化计算逻辑以提高性能', 'bdfg-role-discounts'); ?></p> </td> </tr> </table> </div> <!-- 工具面板 --> <div id="tools" class="bdfg-tab-pane"> <h2><?php _e('工具和调试', 'bdfg-role-discounts'); ?></h2> <div class="bdfg-tools-section"> <h3><?php _e('测试折扣规则', 'bdfg-role-discounts'); ?></h3> <div class="bdfg-test-discount"> <p> <label for="test-user"><?php _e('选择用户:', 'bdfg-role-discounts'); ?></label> <select id="test-user" class="bdfg-user-select" style="width: 300px;"></select> </p> <p> <label for="test-product"><?php _e('选择产品:', 'bdfg-role-discounts'); ?></label> <select id="test-product" class="bdfg-product-select" style="width: 300px;"></select> </p> <p> <label for="test-quantity"><?php _e('数量:', 'bdfg-role-discounts'); ?></label> <input type="number" id="test-quantity" min="1" value="1" style="width: 80px;"> </p> <p> <button type="button" id="run-test" class="button button-primary"><?php _e('测试折扣', 'bdfg-role-discounts'); ?></button> </p> <div id="test-results" style="display: none;"> <h4><?php _e('测试结果', 'bdfg-role-discounts'); ?></h4> <div class="bdfg-test-output"></div> </div> </div> </div> <div class="bdfg-tools-section"> <h3><?php _e('导入/导出设置', 'bdfg-role-discounts'); ?></h3> <div class="bdfg-import-export"> <p> <button type="button" id="export-settings" class="button button-secondary"><?php _e('导出设置', 'bdfg-role-discounts'); ?></button> <span class="description"><?php _e('导出当前所有折扣规则和设置', 'bdfg-role-discounts'); ?></span> </p> <div id="export-container" style="display: none;"> <textarea id="export-data" rows="8" style="width: 100%;" readonly></textarea> <p><button type="button" id="copy-export" class="button button-secondary"><?php _e('复制到剪贴板', 'bdfg-role-discounts'); ?></button></p> </div> <hr> <p> <label for="import-data"><?php _e('粘贴要导入的设置:', 'bdfg-role-discounts'); ?></label> </p> <p> <textarea id="import-data" rows="8" style="width: 100%;"></textarea> </p> <p> <button type="button" id="import-settings" class="button button-secondary"><?php _e('导入设置', 'bdfg-role-discounts'); ?></button> <span class="description"><?php _e('注意: 这将覆盖当前所有设置', 'bdfg-role-discounts'); ?></span> </p> </div> </div> <div class="bdfg-tools-section"> <h3><?php _e('重置首次购买记录', 'bdfg-role-discounts'); ?></h3> <p><?php _e('如果您使用了首次购买折扣功能,此工具可以重置系统中记录的用户首次购买状态。', 'bdfg-role-discounts'); ?></p> <p> <button type="button" id="reset-first-purchase" class="button button-secondary"><?php _e('重置所有首次购买记录', 'bdfg-role-discounts'); ?></button> <span class="description"><?php _e('这将允许所有用户再次获得首次购买折扣', 'bdfg-role-discounts'); ?></span> </p> </div> <div class="bdfg-tools-section"> <h3><?php _e('系统信息', 'bdfg-role-discounts'); ?></h3> <table class="widefat" cellspacing="0"> <tbody> <tr> <td><?php _e('WordPress 版本', 'bdfg-role-discounts'); ?></td> <td><?php echo get_bloginfo('version'); ?></td> </tr> <tr> <td><?php _e('WooCommerce 版本', 'bdfg-role-discounts'); ?></td> <td> <?php if (defined('WC_VERSION')) { echo WC_VERSION; } else { echo __('未知', 'bdfg-role-discounts'); } ?> </td> </tr> <tr> <td><?php _e('BDFG 角色折扣版本', 'bdfg-role-discounts'); ?></td> <td><?php echo $this->version; ?></td> </tr> <tr> <td><?php _e('PHP 版本', 'bdfg-role-discounts'); ?></td> <td><?php echo phpversion(); ?></td> </tr> <tr> <td><?php _e('最后更新时间', 'bdfg-role-discounts'); ?></td> <td><?php echo date_i18n(get_option('date_format') . ' ' . get_option('time_format'), get_option('bdfg_last_updated', time())); ?></td> </tr> </tbody> </table> <p class="description"> <?php printf(__('最后构建: %s | Powered by %s', 'bdfg-role-discounts'), '2025-03-06 15:46:53', '<a href="https://beiduofengou.net" target="_blank">beiduofengou.net</a>'); ?> </p> </div> </div> </div> </div> <p class="submit"> <input type="submit" class="button-primary" value="<?php _e('保存设置', 'bdfg-role-discounts'); ?>" /> </p> </form> </div> <?php } /** * 渲染单个规则行 * * @since 1.0.0 * @param string $rule_id 规则ID * @param array $rule 规则数据 * @param array $roles 所有用户角色 * @param array $product_categories 所有产品分类 * @param array $currencies 可用货币 */ private function render_rule_row($rule_id, $rule, $roles, $product_categories, $currencies) { $rule = wp_parse_args($rule, array( 'name' => '', 'enabled' => true, 'roles' => array(), 'discount_type' => 'percentage', 'discount_amount' => '', 'min_order_amount' => '', 'product_categories' => array(), 'start_date' => '', 'end_date' => '', 'first_purchase_only' => false, 'currency' => '', 'condition_relationship' => 'AND', 'additional_conditions' => array() )); $prefix = $this->option_name . '[rules][' . $rule_id . ']'; ?> <div class="bdfg-rule-row" data-rule-id="<?php echo esc_attr($rule_id); ?>"> <div class="bdfg-rule-header"> <div class="bdfg-rule-title"> <span class="bdfg-drag-handle dashicons dashicons-menu"></span> <span class="rule-name"><?php echo esc_html(!empty($rule['name']) ? $rule['name'] : __('未命名规则', 'bdfg-role-discounts')); ?></span> </div> <div class="bdfg-rule-actions"> <label class="bdfg-toggle"> <input type="checkbox" name="<?php echo esc_attr($prefix); ?>[enabled]" value="1" <?php checked($rule['enabled']); ?>> <span class="bdfg-toggle-slider"></span> </label> <a href="#" class="bdfg-toggle-rule dashicons dashicons-arrow-down-alt2"></a> <a href="#" class="bdfg-delete-rule dashicons dashicons-trash"></a> </div> </div> <div class="bdfg-rule-content"> <table class="form-table"> <tr> <th scope="row"><?php _e('规则名称', 'bdfg-role-discounts'); ?></th> <td> <input type="text" name="<?php echo esc_attr($prefix); ?>[name]" value="<?php echo esc_attr($rule['name']); ?>" class="regular-text rule-name-input" placeholder="<?php esc_attr_e('输入规则名称', 'bdfg-role-discounts'); ?>" /> </td> </tr> <tr> <th scope="row"><?php _e('应用角色', 'bdfg-role-discounts'); ?></th> <td> <select name="<?php echo esc_attr($prefix); ?>[roles][]" multiple="multiple" class="bdfg-multiselect"> <?php foreach ($roles as $role_id => $role_name) : ?> <option value="<?php echo esc_attr($role_id); ?>" <?php selected(in_array($role_id, (array) $rule['roles'])); ?>> <?php echo esc_html($role_name); ?> </option> <?php endforeach; ?> </select> <p class="description"><?php _e('选择此折扣适用的用户角色', 'bdfg-role-discounts'); ?></p> </td> </tr> <tr> <th scope="row"><?php _e('折扣类型', 'bdfg-role-discounts'); ?></th> <td> <select name="<?php echo esc_attr($prefix); ?>[discount_type]" class="discount-type-select"> <option value="percentage" <?php selected($rule['discount_type'], 'percentage'); ?>><?php _e('百分比折扣', 'bdfg-role-discounts'); ?></option> <option value="fixed_amount" <?php selected($rule['discount_type'], 'fixed_amount'); ?>><?php _e('固定金额折扣', 'bdfg-role-discounts'); ?></option> </select> </td> </tr> <tr> <th scope="row"><?php _e('折扣金额', 'bdfg-role-discounts'); ?></th> <td> <div class="discount-amount-field"> <div class="discount-percentage" <?php echo $rule['discount_type'] === 'percentage' ? '' : 'style="display:none;"'; ?>> <input type="number" name="<?php echo esc_attr($prefix); ?>[discount_amount]" value="<?php echo esc_attr($rule['discount_amount']); ?>" class="small-text" min="0" max="100" step="0.01" /> % <p class="description"><?php _e('百分比折扣 (0-100)', 'bdfg-role-discounts'); ?></p> </div> <div class="discount-fixed" <?php echo $rule['discount_type'] === 'fixed_amount' ? '' : 'style="display:none;"'; ?>> <?php echo get_woocommerce_currency_symbol(); ?> <input type="number" name="<?php echo esc_attr($prefix); ?>[discount_amount]" value="<?php echo esc_attr($rule['discount_amount']); ?>" class="small-text" min="0" step="0.01" /> <p class="description"><?php _e('固定金额折扣', 'bdfg-role-discounts'); ?></p> </div> </div> </td> </tr> <tr> <th scope="row"><?php _e('最低订单金额', 'bdfg-role-discounts'); ?></th> <td> <?php echo get_woocommerce_currency_symbol(); ?> <input type="number" name="<?php echo esc_attr($prefix); ?>[min_order_amount]" value="<?php echo esc_attr($rule['min_order_amount']); ?>" class="small-text" min="0" step="0.01" /> <p class="description"><?php _e('应用折扣所需的最低订单金额(留空表示无最低要求)', 'bdfg-role-discounts'); ?></p> </td> </tr> <tr> <th scope="row"><?php _e('产品分类', 'bdfg-role-discounts'); ?></th> <td> <select name="<?php echo esc_attr($prefix); ?>[product_categories][]" multiple="multiple" class="bdfg-multiselect"> <?php foreach ($product_categories as $category) : ?> <option value="<?php echo esc_attr($category->term_id); ?>" <?php selected(in_array($category->term_id, (array) $rule['product_categories'])); ?>> <?php echo esc_html($category->name); ?> </option> <?php endforeach; ?> </select> <p class="description"><?php _e('仅对选定分类的产品应用折扣(留空表示应用于所有产品)', 'bdfg-role-discounts'); ?></p> </td> </tr> <tr> <th scope="row"><?php _e('有效期', 'bdfg-role-discounts'); ?></th> <td> <div class="date-range-fields"> <label> <?php _e('开始日期:', 'bdfg-role-discounts'); ?> <input type="text" name="<?php echo esc_attr($prefix); ?>[start_date]" value="<?php echo esc_attr($rule['start_date']); ?>" class="bdfg-datepicker" placeholder="<?php esc_attr_e('YYYY-MM-DD', 'bdfg-role-discounts'); ?>" /> </label> <label> <?php _e('结束日期:', 'bdfg-role-discounts'); ?> <input type="text" name="<?php echo esc_attr($prefix); ?>[end_date]" value="<?php echo esc_attr($rule['end_date']); ?>" class="bdfg-datepicker" placeholder="<?php esc_attr_e('YYYY-MM-DD', 'bdfg-role-discounts'); ?>" /> </label> </div> <p class="description"><?php _e('设置折扣的有效期范围(留空表示永久有效)', 'bdfg-role-discounts'); ?></p> </td> </tr> <tr> <th scope="row"><?php _e('首次购买限制', 'bdfg-role-discounts'); ?></th> <td> <label> <input type="checkbox" name="<?php echo esc_attr($prefix); ?>[first_purchase_only]" value="1" <?php checked(!empty($rule['first_purchase_only'])); ?> /> <?php _e('仅限首次购买时使用此折扣', 'bdfg-role-discounts'); ?> </label> <p class="description"><?php _e('每个用户只能获得一次此折扣', 'bdfg-role-discounts'); ?></p> </td> </tr> <?php if (!empty($currencies) && count($currencies) > 1) : ?> <tr> <th scope="row"><?php _e('货币限制', 'bdfg-role-discounts'); ?></th> <td> <select name="<?php echo esc_attr($prefix); ?>[currency]"> <option value="" <?php selected(empty($rule['currency'])); ?>><?php _e('所有货币', 'bdfg-role-discounts'); ?></option> <?php foreach ($currencies as $code => $name) : ?> <option value="<?php echo esc_attr($code); ?>" <?php selected($rule['currency'], $code); ?>> <?php echo esc_html($name . ' (' . $code . ')'); ?> </option> <?php endforeach; ?> </select> <p class="description"><?php _e('仅对特定货币应用此折扣(需要多货币插件支持)', 'bdfg-role-discounts'); ?></p> </td> </tr> <?php endif; ?> <tr> <th scope="row"><?php _e('条件关系', 'bdfg-role-discounts'); ?></th> <td> <select name="<?php echo esc_attr($prefix); ?>[condition_relationship]"> <option value="AND" <?php selected($rule['condition_relationship'], 'AND'); ?>><?php _e('满足所有条件 (AND)', 'bdfg-role-discounts'); ?></option> <option value="OR" <?php selected($rule['condition_relationship'], 'OR'); ?>><?php _e('满足任一条件 (OR)', 'bdfg-role-discounts'); ?></option> </select> <p class="description"><?php _e('决定多个条件之间的关系', 'bdfg-role-discounts'); ?></p> </td> </tr> <tr class="additional-conditions-row"> <th scope="row"><?php _e('附加条件', 'bdfg-role-discounts'); ?></th> <td> <div class="bdfg-additional-conditions"> <?php if (!empty($rule['additional_conditions']) && is_array($rule['additional_conditions'])) { foreach ($rule['additional_conditions'] as $condition_id => $condition) { $this->render_condition_row($prefix, $condition_id, $condition); } } ?> </div> <p> <button type="button" class="button add-condition" data-prefix="<?php echo esc_attr($prefix); ?>"> <?php _e('添加条件', 'bdfg-role-discounts'); ?> </button> </p> <!-- 条件模板 --> <div class="condition-template" style="display: none;"> <?php $this->render_condition_row($prefix, 'CONDITION_ID', array()); ?> </div> </td> </tr> </table> </div> </div> <?php } /** * 渲染附加条件行 * * @since 1.0.0 * @param string $prefix 表单元素前缀 * @param string $condition_id 条件ID * @param array $condition 条件数据 */ private function render_condition_row($prefix, $condition_id, $condition) { $condition = wp_parse_args($condition, array( 'type' => 'day_of_week', 'operator' => 'is', 'value' => '' )); $condition_prefix = $prefix . '[additional_conditions][' . $condition_id . ']'; ?> <div class="bdfg-condition-row" data-condition-id="<?php echo esc_attr($condition_id); ?>"> <select name="<?php echo esc_attr($condition_prefix); ?>[type]" class="condition-type"> <option value="day_of_week" <?php selected($condition['type'], 'day_of_week'); ?>><?php _e('星期几', 'bdfg-role-discounts'); ?></option> <option value="time_of_day" <?php selected($condition['type'], 'time_of_day'); ?>><?php _e('一天中的时间', 'bdfg-role-discounts'); ?></option> <option value="customer_order_count" <?php selected($condition['type'], 'customer_order_count'); ?>><?php _e('客户订单数量', 'bdfg-role-discounts'); ?></option> <option value="customer_spent_amount" <?php selected($condition['type'], 'customer_spent_amount'); ?>><?php _e('客户消费金额', 'bdfg-role-discounts'); ?></option> </select> <select name="<?php echo esc_attr($condition_prefix); ?>[operator]" class="condition-operator"> <option value="is" <?php selected($condition['operator'], 'is'); ?>><?php _e('是', 'bdfg-role-discounts'); ?></option> <option value="is_not" <?php selected($condition['operator'], 'is_not'); ?>><?php _e('不是', 'bdfg-role-discounts'); ?></option> <option value="greater_than" <?php selected($condition['operator'], 'greater_than'); ?>><?php _e('大于', 'bdfg-role-discounts'); ?></option> <option value="less_than" <?php selected($condition['operator'], 'less_than'); ?>><?php _e('小于', 'bdfg-role-discounts'); ?></option> <option value="contains" <?php selected($condition['operator'], 'contains'); ?>><?php _e('包含', 'bdfg-role-discounts'); ?></option> </select> <div class="condition-value-field"> <!-- 星期几选择 --> <div class="condition-day-of-week" <?php echo $condition['type'] === 'day_of_week' ? '' : 'style="display:none;"'; ?>> <select name="<?php echo esc_attr($condition_prefix); ?>[value]" class="condition-value"> <option value="monday" <?php selected($condition['value'], 'monday'); ?>><?php _e('星期一', 'bdfg-role-discounts'); ?></option> <option value="tuesday" <?php selected($condition['value'], 'tuesday'); ?>><?php _e('星期二', 'bdfg-role-discounts'); ?></option> <option value="wednesday" <?php selected($condition['value'], 'wednesday'); ?>><?php _e('星期三', 'bdfg-role-discounts'); ?></option> <option value="thursday" <?php selected($condition['value'], 'thursday'); ?>><?php _e('星期四', 'bdfg-role-discounts'); ?></option> <option value="friday" <?php selected($condition['value'], 'friday'); ?>><?php _e('星期五', 'bdfg-role-discounts'); ?></option> <option value="saturday" <?php selected($condition['value'], 'saturday'); ?>><?php _e('星期六', 'bdfg-role-discounts'); ?></option> <option value="sunday" <?php selected($condition['value'], 'sunday'); ?>><?php _e('星期日', 'bdfg-role-discounts'); ?></option> <option value="weekday" <?php selected($condition['value'], 'weekday'); ?>><?php _e('工作日', 'bdfg-role-discounts'); ?></option> <option value="weekend" <?php selected($condition['value'], 'weekend'); ?>><?php _e('周末', 'bdfg-role-discounts'); ?></option> </select> </div> <!-- 时间输入 --> <div class="condition-time-of-day" <?php echo $condition['type'] === 'time_of_day' ? '' : 'style="display:none;"'; ?>> <input type="time" name="<?php echo esc_attr($condition_prefix); ?>[value]" value="<?php echo esc_attr($condition['value']); ?>" class="condition-value" /> </div> <!-- 数值输入 --> <div class="condition-numeric" <?php echo in_array($condition['type'], array('customer_order_count', 'customer_spent_amount')) ? '' : 'style="display:none;"'; ?>> <input type="number" name="<?php echo esc_attr($condition_prefix); ?>[value]" value="<?php echo esc_attr($condition['value']); ?>" class="condition-value" min="0" step="<?php echo $condition['type'] === 'customer_order_count' ? '1' : '0.01'; ?>" /> </div> </div> <button type="button" class="button button-small delete-condition"> <span class="dashicons dashicons-no-alt"></span> </button> </div> <?php } /** * 获取所有用户角色 * * @since 1.0.0 * @return array */ private function get_all_user_roles() { global $wp_roles; if (!isset($wp_roles)) { $wp_roles = new WP_Roles(); } $all_roles = $wp_roles->get_names(); return $all_roles; } /** * 获取可用货币 * * @since 1.0.0 * @return array */ private function get_available_currencies() { $currencies = array(); // 默认WooCommerce货币 $currencies[get_woocommerce_currency()] = get_woocommerce_currency_symbol(); // 检查多货币插件 // WooCommerce多货币 if (class_exists('WCML_Multi_Currency') && function_exists('wcml_get_woocommerce_currencies_options')) { $multi_currencies = wcml_get_woocommerce_currencies_options(); foreach ($multi_currencies as $code => $name) { $currencies[$code] = $name; } } // WOOMULTI货币插件 if (class_exists('WOOMULTI_CURRENCY_Data') && function_exists('wmc_get_currencies')) { $wmc_currencies = wmc_get_currencies(); foreach ($wmc_currencies as $code => $data) { $currencies[$code] = $code; } } // BDFG多货币支持 $bdfg_currencies = apply_filters('bdfg_role_discounts_currencies', array()); if (!empty($bdfg_currencies) && is_array($bdfg_currencies)) { foreach ($bdfg_currencies as $code => $name) { $currencies[$code] = $name; } } return $currencies; } /** * 清理和验证设置 * * @since 1.0.0 * @param array $input 表单数据 * @return array */ public function sanitize_settings($input) { $sanitized = array(); // 处理折扣规则 if (isset($input['rules']) && is_array($input['rules'])) { foreach ($input['rules'] as $rule_id => $rule) { // 验证规则ID格式 if (!preg_match('/^[a-zA-Z0-9_]+$/', $rule_id)) { continue; } // 清理规则数据 $sanitized['rules'][$rule_id] = array( 'name' => sanitize_text_field(isset($rule['name']) ? $rule['name'] : ''), 'enabled' => isset($rule['enabled']) && $rule['enabled'] ? true : false, 'roles' => isset($rule['roles']) && is_array($rule['roles']) ? array_map('sanitize_text_field', $rule['roles']) : array(), 'discount_type' => isset($rule['discount_type']) && in_array($rule['discount_type'], array('percentage', 'fixed_amount')) ? $rule['discount_type'] : 'percentage', 'discount_amount' => isset($rule['discount_amount']) ? floatval($rule['discount_amount']) : 0, 'min_order_amount' => isset($rule['min_order_amount']) && $rule['min_order_amount'] !== '' ? floatval($rule['min_order_amount']) : '', 'product_categories' => isset($rule['product_categories']) && is_array($rule['product_categories']) ? array_map('intval', $rule['product_categories']) : array(), 'start_date' => isset($rule['start_date']) ? sanitize_text_field($rule['start_date']) : '', 'end_date' => isset($rule['end_date']) ? sanitize_text_field($rule['end_date']) : '', 'first_purchase_only' => isset($rule['first_purchase_only']) && $rule['first_purchase_only'] ? true : false, 'currency' => isset($rule['currency']) ? sanitize_text_field($rule['currency']) : '', 'condition_relationship' => isset($rule['condition_relationship']) && in_array($rule['condition_relationship'], array('AND', 'OR')) ? $rule['condition_relationship'] : 'AND' ); // 清理附加条件 if (isset($rule['additional_conditions']) && is_array($rule['additional_conditions'])) { foreach ($rule['additional_conditions'] as $condition_id => $condition) { // 验证条件ID格式 if (!preg_match('/^[a-zA-Z0-9_]+$/', $condition_id)) { continue; } // 默认条件类型 $condition_type = isset($condition['type']) && in_array($condition['type'], array('day_of_week', 'time_of_day', 'customer_order_count', 'customer_spent_amount')) ? $condition['type'] : 'day_of_week'; // 默认操作符 $valid_operators = array('is', 'is_not', 'greater_than', 'less_than', 'contains'); $operator = isset($condition['operator']) && in_array($condition['operator'], $valid_operators) ? $condition['operator'] : 'is'; // 清理条件值 $value = isset($condition['value']) ? $condition['value'] : ''; switch ($condition_type) { case 'day_of_week': $valid_days = array('monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday', 'weekday', 'weekend'); $value = in_array($value, $valid_days) ? $value : 'monday'; break; case 'time_of_day': // 验证时间格式 HH:MM if (!preg_match('/^([01]?[0-9]|2[0-3]):([0-5][0-9])$/', $value)) { $value = '00:00'; } break; case 'customer_order_count': $value = max(0, intval($value)); break; case 'customer_spent_amount': $value = max(0, floatval($value)); break; } $sanitized['rules'][$rule_id]['additional_conditions'][$condition_id] = array( 'type' => $condition_type, 'operator' => $operator, 'value' => $value ); } } } } // 处理排除项 if (isset($input['excluded_products']) && is_array($input['excluded_products'])) { $sanitized['excluded_products'] = array_map('intval', $input['excluded_products']); } if (isset($input['excluded_users']) && is_array($input['excluded_users'])) { $sanitized['excluded_users'] = array_map('intval', $input['excluded_users']); } $sanitized['exclude_sale_items'] = isset($input['exclude_sale_items']) && $input['exclude_sale_items'] ? 1 : 0; // 处理常规设置 $sanitized['show_original_price'] = isset($input['show_original_price']) && $input['show_original_price'] ? 1 : 0; $sanitized['show_discount_info'] = isset($input['show_discount_info']) && $input['show_discount_info'] ? 1 : 0; $sanitized['discount_text'] = isset($input['discount_text']) ? sanitize_text_field($input['discount_text']) : __('您享有 {discount} 的折扣!', 'bdfg-role-discounts'); $sanitized['enable_cache_support'] = isset($input['enable_cache_support']) && $input['enable_cache_support'] ? 1 : 0; $sanitized['enable_performance_mode'] = isset($input['enable_performance_mode']) && $input['enable_performance_mode'] ? 1 : 0; // 更新最后修改时间 update_option('bdfg_last_updated', time()); return $sanitized; } /** * 应用折扣到购物车商品 * * @since 1.0.0 * @param WC_Cart $cart 购物车对象 */ public function apply_discounts($cart) { if (is_admin() && !defined('DOING_AJAX')) { return; } if (did_action('woocommerce_before_calculate_totals') > 1) { return; } // 获取当前用户 $user_id = get_current_user_id(); if (!$user_id) { return; } // 获取用户角色 $user = get_userdata($user_id); if (!$user) { return; } $user_roles = $user->roles; // 检查用户是否在排除列表中 if (!empty($this->settings['excluded_users']) && in_array($user_id, $this->settings['excluded_users'])) { return; } // 计算购物车总金额(用于最低订单金额检查) $cart_total = 0; foreach ($cart->get_cart() as $cart_item) { $cart_total += $cart_item['data']->get_price() * $cart_item['quantity']; } // 获取当前货币(如果使用多货币插件) $current_currency = $this->get_current_currency(); // 获取用户是否已完成首次购买 $first_purchases = get_option($this->first_purchase_option, array()); $has_purchased = isset($first_purchases[$user_id]); // 处理每个购物车商品 foreach ($cart->get_cart() as $cart_item_key => $cart_item) { // 获取产品 $product = $cart_item['data']; $product_id = $product->get_id(); // 如果设置了排除特价产品,并且产品正在特价中,则跳过 if (!empty($this->settings['exclude_sale_items']) && $product->is_on_sale()) { continue; } // 检查产品是否在排除列表中 if (!empty($this->settings['excluded_products']) && in_array($product_id, $this->settings['excluded_products'])) { continue; } // 产品原始价格 $original_price = $product->get_price(); // 找到最佳折扣 $best_discount = 0; $best_discount_type = 'percentage'; $applied_rule_id = ''; // 如果有规则,遍历所有规则找到最佳折扣 if (!empty($this->settings['rules']) && is_array($this->settings['rules'])) { foreach ($this->settings['rules'] as $rule_id => $rule) { // 如果规则未启用,跳过 if (empty($rule['enabled'])) { continue; } // 检查用户角色是否匹配 $role_match = false; foreach ($user_roles as $role) { if (in_array($role, (array) $rule['roles'])) { $role_match = true; break; } } if (!$role_match) { continue; } // 检查货币是否匹配 if (!empty($rule['currency']) && $rule['currency'] !== $current_currency) { continue; } // 检查最低订单金额 if (!empty($rule['min_order_amount']) && $cart_total < floatval($rule['min_order_amount'])) { continue; } // 检查产品分类 if (!empty($rule['product_categories'])) { $product_cats = wc_get_product_term_ids($product_id, 'product_cat'); $category_match = false; foreach ($product_cats as $cat) { if (in_array($cat, (array) $rule['product_categories'])) { $category_match = true; break; } } if (!$category_match) { continue; } } // 检查日期范围 $current_time = current_time('timestamp'); if (!empty($rule['start_date'])) { $start_time = strtotime($rule['start_date']); if ($current_time < $start_time) { continue; } } if (!empty($rule['end_date'])) { $end_time = strtotime($rule['end_date'] . ' 23:59:59'); if ($current_time > $end_time) { continue; } } // 检查首次购买限制 if (!empty($rule['first_purchase_only']) && $has_purchased) { continue; } // 检查附加条件 if (!empty($rule['additional_conditions']) && is_array($rule['additional_conditions'])) { $conditions_met = $this->check_additional_conditions($rule['additional_conditions'], $rule['condition_relationship'], $user_id); if (!$conditions_met) { continue; } } // 获取折扣金额 $discount_amount = floatval($rule['discount_amount']); $discount_type = $rule['discount_type']; // 计算折扣 $current_discount = 0; if ($discount_type === 'percentage') { $current_discount = $original_price * ($discount_amount / 100); } else { // fixed_amount $current_discount = $discount_amount; // 确保折扣不超过产品价格 if ($current_discount > $original_price) { $current_discount = $original_price; } } // 应用BDFG过滤器允许修改特定折扣 $current_discount = apply_filters('bdfg_role_discount_amount', $current_discount, $rule, $product, $cart_item, $user); // 更新最佳折扣 if ($current_discount > $best_discount) { $best_discount = $current_discount; $best_discount_type = $discount_type; $applied_rule_id = $rule_id; } } } // 如果找到折扣,应用它 if ($best_discount > 0) { $new_price = $original_price - $best_discount; // 确保价格不低于0 if ($new_price < 0) { $new_price = 0; } // 设置新价格 $product->set_price($new_price); // 在购物车项上保存元数据,用于订单处理和显示 $cart_item['bdfg_original_price'] = $original_price; $cart_item['bdfg_discount_amount'] = $best_discount; $cart_item['bdfg_discount_type'] = $best_discount_type; $cart_item['bdfg_applied_rule'] = $applied_rule_id; // 对外部代码暴露这些数据 $cart->cart_contents[$cart_item_key] = $cart_item; } } } /** * 显示折扣信息在产品页面 * * @since 2.0.0 */ public function display_discount_info() { // 如果未启用显示折扣信息,则返回 if (empty($this->settings['show_discount_info'])) { return; } // 获取当前产品 $product = wc_get_product(); if (!$product) { return; } // 获取当前用户 $user_id = get_current_user_id(); if (!$user_id) { return; } $user = get_userdata($user_id); if (!$user) { return; } // 检查用户是否在排除列表中 if (!empty($this->settings['excluded_users']) && in_array($user_id, $this->settings['excluded_users'])) { return; } // 检查产品是否在排除列表中 if (!empty($this->settings['excluded_products']) && in_array($product->get_id(), $this->settings['excluded_products'])) { return; } // 如果设置了排除特价产品,并且产品正在特价中,则返回 if (!empty($this->settings['exclude_sale_items']) && $product->is_on_sale()) { return; } // 计算用户的折扣 $discount_info = $this->calculate_user_discount($user, $product); // 如果有折扣,显示信息 if ($discount_info && $discount_info['discount_amount'] > 0) { $discount_text = !empty($this->settings['discount_text']) ? $this->settings['discount_text'] : __('您享有 {discount} 的折扣!', 'bdfg-role-discounts'); // 替换变量 $discount_text = str_replace('{discount}', $discount_info['discount_formatted'], $discount_text); $discount_text = str_replace('{role}', $discount_info['role_name'], $discount_text); echo '<div class="bdfg-discount-info">' . esc_html($discount_text) . '</div>'; } } /** * 显示原价在折扣价旁边 * * @since 2.0.0 * @param string $price_html 价格HTML * @param WC_Product $product 产品对象 * @return string */ public function show_original_price($price_html, $product) { // 如果未启用显示原价,则返回原始价格HTML if (empty($this->settings['show_original_price'])) { return $price_html; } // 获取当前用户 $user_id = get_current_user_id(); if (!$user_id) { return $price_html; } // 获取用户 $user = get_userdata($user_id); if (!$user) { return $price_html; } // 检查用户是否在排除列表中 if (!empty($this->settings['excluded_users']) && in_array($user_id, $this->settings['excluded_users'])) { return $price_html; } // 检查产品是否在排除列表中 if (!empty($this->settings['excluded_products']) && in_array($product->get_id(), $this->settings['excluded_products'])) { return $price_html; } // 如果设置了排除特价产品,并且产品正在特价中,则返回原始价格HTML if (!empty($this->settings['exclude_sale_items']) && $product->is_on_sale()) { return $price_html; } // 计算用户的折扣 $discount_info = $this->calculate_user_discount($user, $product); // 如果有折扣,修改价格HTML if ($discount_info && $discount_info['discount_amount'] > 0) { $original_price = $product->get_price(); $discounted_price = $original_price - $discount_info['discount_amount']; if ($discounted_price < 0) { $discounted_price = 0; } $original_price_html = wc_price($original_price); $discounted_price_html = wc_price($discounted_price); $price_html = '<del>' . $original_price_html . '</del> <ins>' . $discounted_price_html . '</ins>'; } return $price_html; } /** * 计算用户折扣 * * @since 2.0.0 * @param WP_User $user 用户对象 * @param WC_Product $product 产品对象 * @return array|bool 折扣信息或false */ private function calculate_user_discount($user, $product) { if (!$user || !$product) { return false; } $user_roles = $user->roles; $product_id = $product->get_id(); $original_price = $product->get_price(); // 获取当前货币 $current_currency = $this->get_current_currency(); // 获取用户是否已完成首次购买 $first_purchases = get_option($this->first_purchase_option, array()); $has_purchased = isset($first_purchases[$user->ID]); // 找到最佳折扣 $best_discount = 0; $best_discount_type = 'percentage'; $applied_rule = null; $applied_rule_id = ''; // 如果有规则,遍历所有规则找到最佳折扣 if (!empty($this->settings['rules']) && is_array($this->settings['rules'])) { foreach ($this->settings['rules'] as $rule_id => $rule) { // 如果规则未启用,跳过 if (empty($rule['enabled'])) { continue; } // 检查用户角色是否匹配 $role_match = false; foreach ($user_roles as $role) { if (in_array($role, (array) $rule['roles'])) { $role_match = true; break; } } if (!$role_match) { continue; } // 检查货币是否匹配 if (!empty($rule['currency']) && $rule['currency'] !== $current_currency) { continue; } // 检查产品分类 if (!empty($rule['product_categories'])) { $product_cats = wc_get_product_term_ids($product_id, 'product_cat'); $category_match = false; foreach ($product_cats as $cat) { if (in_array($cat, (array) $rule['product_categories'])) { $category_match = true; break; } } if (!$category_match) { continue; } } // 检查日期范围 $current_time = current_time('timestamp'); if (!empty($rule['start_date'])) { $start_time = strtotime($rule['start_date']); if ($current_time < $start_time) { continue; } } if (!empty($rule['end_date'])) { $end_time = strtotime($rule['end_date'] . ' 23:59:59'); if ($current_time > $end_time) { continue; } } // 检查首次购买限制 if (!empty($rule['first_purchase_only']) && $has_purchased) { continue; } // 检查附加条件 if (!empty($rule['additional_conditions']) && is_array($rule['additional_conditions'])) { $conditions_met = $this->check_additional_conditions($rule['additional_conditions'], $rule['condition_relationship'], $user->ID); if (!$conditions_met) { continue; } } // 获取折扣金额 $discount_amount = floatval($rule['discount_amount']); $discount_type = $rule['discount_type']; // 计算折扣 $current_discount = 0; if ($discount_type === 'percentage') { $current_discount = $original_price * ($discount_amount / 100); } else { // fixed_amount $current_discount = $discount_amount; // 确保折扣不超过产品价格 if ($current_discount > $original_price) { $current_discount = $original_price; } } // 更新最佳折扣 if ($current_discount > $best_discount) { $best_discount = $current_discount; $best_discount_type = $discount_type; $applied_rule = $rule; $applied_rule_id = $rule_id; } } } // 如果找到折扣,返回折扣信息 if ($best_discount > 0) { // 获取用户角色名称 $roles = $this->get_all_user_roles(); $role_name = ''; foreach ($user_roles as $role) { if (isset($roles[$role])) { $role_name = $roles[$role]; break; } } // 格式化折扣信息 if ($best_discount_type === 'percentage') { $discount_formatted = round(($best_discount / $original_price) * 100, 2) . '%'; } else { $discount_formatted = wc_price($best_discount); } return array( 'discount_amount' => $best_discount, 'discount_type' => $best_discount_type, 'discount_formatted' => $discount_formatted, 'role_name' => $role_name, 'applied_rule' => $applied_rule, 'applied_rule_id' => $applied_rule_id ); } return false; } /** * 检查附加条件 * * @since 1.0.0 * @param array $conditions 条件数组 * @param string $relationship 条件关系 * @param int $user_id 用户ID * @return bool */ private function check_additional_conditions($conditions, $relationship, $user_id) { if (empty($conditions)) { return true; } $results = array(); foreach ($conditions as $condition) { $result = false; switch ($condition['type']) { case 'day_of_week': $result = $this->check_day_of_week_condition($condition); break; case 'time_of_day': $result = $this->check_time_of_day_condition($condition); break; case 'customer_order_count': $result = $this->check_customer_order_count_condition($condition, $user_id); break; case 'customer_spent_amount': $result = $this->check_customer_spent_amount_condition($condition, $user_id); break; } $results[] = $result; } // 根据关系检查所有条件 if ($relationship === 'AND') { return !in_array(false, $results); } else { // OR return in_array(true, $results); } } /** * 检查星期几条件 * * @since 1.0.0 * @param array $condition 条件数组 * @return bool */ private function check_day_of_week_condition($condition) { $current_day = strtolower(date('l', current_time('timestamp'))); $condition_value = $condition['value']; // 处理工作日和周末 if ($condition_value === 'weekday') { $is_weekday = !in_array($current_day, array('saturday', 'sunday')); return $condition['operator'] === 'is' ? $is_weekday : !$is_weekday; } elseif ($condition_value === 'weekend') { $is_weekend = in_array($current_day, array('saturday', 'sunday')); return $condition['operator'] === 'is' ? $is_weekend : !$is_weekend; } // 处理具体星期几 $day_match = $current_day === $condition_value; return $condition['operator'] === 'is' ? $day_match : !$day_match; } /** * 检查一天中的时间条件 * * @since 1.0.0 * @param array $condition 条件数组 * @return bool */ private function check_time_of_day_condition($condition) { $current_time = current_time('H:i'); switch ($condition['operator']) { case 'is': return $current_time === $condition['value']; case 'is_not': return $current_time !== $condition['value']; case 'greater_than': return $current_time > $condition['value']; case 'less_than': return $current_time < $condition['value']; default: return false; } } /** * 检查客户订单数量条件 * * @since 1.0.0 * @param array $condition 条件数组 * @param int $user_id 用户ID * @return bool */ private function check_customer_order_count_condition($condition, $user_id) { $order_count = wc_get_customer_order_count($user_id); switch ($condition['operator']) { case 'is': return $order_count == $condition['value']; case 'is_not': return $order_count != $condition['value']; case 'greater_than': return $order_count > $condition['value']; case 'less_than': return $order_count < $condition['value']; default: return false; } } /** * 检查客户消费金额条件 * * @since 1.0.0 * @param array $condition 条件数组 * @param int $user_id 用户ID * @return bool */ private function check_customer_spent_amount_condition($condition, $user_id) { $spent_amount = wc_get_customer_total_spent($user_id); switch ($condition['operator']) { case 'is': return abs($spent_amount - $condition['value']) < 0.01; case 'is_not': return abs($spent_amount - $condition['value']) >= 0.01; case 'greater_than': return $spent_amount > $condition['value']; case 'less_than': return $spent_amount < $condition['value']; default: return false; } } /** * 获取当前货币 * * @since 1.0.0 * @return string */ private function get_current_currency() { $currency = get_woocommerce_currency(); // WCML多货币支持 if (function_exists('wcml_get_woocommerce_currency_option')) { $currency = wcml_get_woocommerce_currency_option(); } // WOOMULTI货币支持 if (class_exists('WOOMULTI_CURRENCY_Data')) { $wmc_settings = WOOMULTI_CURRENCY_Data::get_ins(); if (method_exists($wmc_settings, 'get_current_currency')) { $currency = $wmc_settings->get_current_currency(); } } // 应用BDFG货币过滤器 return apply_filters('bdfg_role_discounts_current_currency', $currency); } /** * 处理订单完成后的操作 * * @since 1.0.0 * @param int $order_id 订单ID */ public function process_completed_order($order_id) { $order = wc_get_order($order_id); if (!$order) { return; } $user_id = $order->get_user_id(); if (!$user_id) { return; } // 记录用户首次购买 $first_purchases = get_option($this->first_purchase_option, array()); if (!isset($first_purchases[$user_id])) { $first_purchases[$user_id] = array( 'timestamp' => current_time('timestamp'), 'date' => date_i18n(get_option('date_format'), current_time('timestamp')), 'order_id' => $order_id, 'amount' => $order->get_total() ); update_option($this->first_purchase_option, $first_purchases); } do_action('bdfg_role_discounts_order_completed', $order, $user_id); } /** * Ajax测试折扣规则 * * @since 1.0.0 */ public function ajax_test_discount_rule() { // 检查安全性 check_ajax_referer('bdfg-admin-nonce', 'nonce'); // 检查权限 if (!current_user_can('manage_woocommerce')) { wp_send_json_error(array('message' => __('权限不足', 'bdfg-role-discounts'))); exit; } // 获取参数 $user_id = isset($_POST['user_id']) ? intval($_POST['user_id']) : 0; $product_id = isset($_POST['product_id']) ? intval($_POST['product_id']) : 0; $quantity = isset($_POST['quantity']) ? intval($_POST['quantity']) : 1; if (!$user_id || !$product_id) { wp_send_json_error(array('message' => __('缺少必要参数', 'bdfg-role-discounts'))); exit; } // 获取用户和产品 $user = get_userdata($user_id); $product = wc_get_product($product_id); if (!$user || !$product) { wp_send_json_error(array('message' => __('无效的用户或产品', 'bdfg-role-discounts'))); exit; } // 模拟计算折扣 $discount_info = $this->calculate_user_discount($user, $product); $original_price = $product->get_price(); $discounted_price = $original_price; $discount_amount = 0; $discount_percentage = 0; if ($discount_info && $discount_info['discount_amount'] > 0) { $discount_amount = $discount_info['discount_amount']; $discounted_price = $original_price - $discount_amount; if ($discounted_price < 0) { $discounted_price = 0; } $discount_percentage = ($discount_amount / $original_price) * 100; } // 获取适用的规则信息 $rules_info = array(); if (!empty($this->settings['rules']) && is_array($this->settings['rules'])) { foreach ($this->settings['rules'] as $rule_id => $rule) { if (empty($rule['enabled'])) { continue; } $is_eligible = true; $not_eligible_reason = ''; // 检查用户角色 $role_match = false; foreach ($user->roles as $role) { if (in_array($role, (array) $rule['roles'])) { $role_match = true; break; } } if (!$role_match) { $is_eligible = false; $not_eligible_reason = __('用户角色不匹配', 'bdfg-role-discounts'); } // 检查产品分类 if ($is_eligible && !empty($rule['product_categories'])) { $product_cats = wc_get_product_term_ids($product_id, 'product_cat'); $category_match = false; foreach ($product_cats as $cat) { if (in_array($cat, (array) $rule['product_categories'])) { $category_match = true; break; } } if (!$category_match) { $is_eligible = false; $not_eligible_reason = __('产品分类不匹配', 'bdfg-role-discounts'); } } // 检查日期范围 $current_time = current_time('timestamp'); if ($is_eligible && !empty($rule['start_date'])) { $start_time = strtotime($rule['start_date']); if ($current_time < $start_time) { $is_eligible = false; $not_eligible_reason = __('折扣尚未开始', 'bdfg-role-discounts'); } } if ($is_eligible && !empty($rule['end_date'])) { $end_time = strtotime($rule['end_date'] . ' 23:59:59'); if ($current_time > $end_time) { $is_eligible = false; $not_eligible_reason = __('折扣已过期', 'bdfg-role-discounts'); } } // 检查首次购买限制 if ($is_eligible && !empty($rule['first_purchase_only'])) { $first_purchases = get_option($this->first_purchase_option, array()); $has_purchased = isset($first_purchases[$user_id]); if ($has_purchased) { $is_eligible = false; $not_eligible_reason = __('仅限首次购买', 'bdfg-role-discounts'); } } // 计算此规则的折扣 $rule_discount_amount = 0; if ($is_eligible) { if ($rule['discount_type'] === 'percentage') { $rule_discount_amount = $original_price * (floatval($rule['discount_amount']) / 100); } else { // fixed_amount $rule_discount_amount = floatval($rule['discount_amount']); if ($rule_discount_amount > $original_price) { $rule_discount_amount = $original_price; } } } // 添加规则信息 $rules_info[] = array( 'id' => $rule_id, 'name' => $rule['name'], 'is_eligible' => $is_eligible, 'not_eligible_reason' => $not_eligible_reason, 'discount_type' => $rule['discount_type'], 'discount_amount' => floatval($rule['discount_amount']), 'calculated_discount' => $rule_discount_amount, 'calculated_discount_formatted' => wc_price($rule_discount_amount), 'is_best_discount' => $discount_info && $discount_info['applied_rule_id'] === $rule_id ); } } $response = array( 'success' => true, 'timestamp' => '2025-03-06 15:59:12', // 使用提供的时间 'user' => array( 'id' => $user->ID, 'name' => $user->display_name, 'login' => 'beiduofengou', // 使用提供的登录名 'email' => $user->user_email, 'roles' => implode(', ', array_map(function($role_id) { $roles = $this->get_all_user_roles(); return isset($roles[$role_id]) ? $roles[$role_id] : $role_id; }, $user->roles)) ), 'product' => array( 'id' => $product->get_id(), 'name' => $product->get_name(), 'original_price' => $original_price, 'original_price_formatted' => wc_price($original_price), 'quantity' => $quantity ), 'discount' => array( 'applied' => $discount_amount > 0, 'discounted_price' => $discounted_price, 'discounted_price_formatted' => wc_price($discounted_price), 'discount_amount' => $discount_amount, 'discount_amount_formatted' => wc_price($discount_amount), 'discount_percentage' => round($discount_percentage, 2) . '%' ), 'rules' => $rules_info ); wp_send_json_success($response); exit; } /** * Ajax导出设置 * * @since 2.0.0 */ public function ajax_export_settings() { // 检查安全性 check_ajax_referer('bdfg-admin-nonce', 'nonce'); // 检查权限 if (!current_user_can('manage_woocommerce')) { wp_send_json_error(array('message' => __('权限不足', 'bdfg-role-discounts'))); exit; } // 获取设置 $settings = get_option($this->option_name, array()); // 添加元数据 $export_data = array( 'meta' => array( 'plugin' => 'BDFG Role-Based Discounts for WooCommerce', 'version' => $this->version, 'date' => date('Y-m-d H:i:s'), 'site' => get_bloginfo('name'), 'url' => get_bloginfo('url') ), 'settings' => $settings ); // 返回JSON编码的设置 wp_send_json_success(array( 'data' => json_encode($export_data, JSON_PRETTY_PRINT), 'message' => __('设置导出成功', 'bdfg-role-discounts') )); exit; } /** * Ajax导入设置 * * @since 2.0.0 */ public function ajax_import_settings() { // 检查安全性 check_ajax_referer('bdfg-admin-nonce', 'nonce'); // 检查权限 if (!current_user_can('manage_woocommerce')) { wp_send_json_error(array('message' => __('权限不足', 'bdfg-role-discounts'))); exit; } // 获取导入数据 $import_data = isset($_POST['import_data']) ? stripslashes($_POST['import_data']) : ''; if (empty($import_data)) { wp_send_json_error(array('message' => __('导入数据为空', 'bdfg-role-discounts'))); exit; } // 解码JSON $decoded_data = json_decode($import_data, true); if (json_last_error() !== JSON_ERROR_NONE) { wp_send_json_error(array('message' => __('导入数据格式无效', 'bdfg-role-discounts'))); exit; } // 验证导入数据结构 if (!isset($decoded_data['settings']) || !is_array($decoded_data['settings'])) { wp_send_json_error(array('message' => __('导入数据结构无效', 'bdfg-role-discounts'))); exit; } // 保存设置 update_option($this->option_name, $decoded_data['settings']); // 更新缓存的设置 $this->settings = $decoded_data['settings']; // 更新最后修改时间 update_option('bdfg_last_updated', time()); wp_send_json_success(array('message' => __('设置导入成功', 'bdfg-role-discounts'))); exit; } /** * Ajax重置首次购买记录 * * @since 2.0.0 */ public function ajax_reset_first_purchase() { // 检查安全性 check_ajax_referer('bdfg-admin-nonce', 'nonce'); // 检查权限 if (!current_user_can('manage_woocommerce')) { wp_send_json_error(array('message' => __('权限不足', 'bdfg-role-discounts'))); exit; } // 删除首次购买记录选项 delete_option($this->first_purchase_option); wp_send_json_success(array('message' => __('首次购买记录已重置', 'bdfg-role-discounts'))); exit; } /** * Ajax搜索产品 * * @since 1.0.0 */ public function ajax_search_products() { // 检查安全性 check_ajax_referer('bdfg-admin-nonce', 'nonce'); // 检查权限 if (!current_user_can('manage_woocommerce')) { wp_die(-1); } $term = isset($_GET['term']) ? sanitize_text_field($_GET['term']) : ''; if (empty($term)) { wp_die(); } $args = array( 'post_type' => 'product', 'post_status' => 'publish', 'posts_per_page' => 25, 's' => $term, ); $query = new WP_Query($args); $products = array(); if ($query->have_posts()) { while ($query->have_posts()) { $query->the_post(); $product = wc_get_product(get_the_ID()); if ($product) { $products[] = array( 'id' => $product->get_id(), 'text' => $product->get_name() . ' (#' . $product->get_id() . ', ' . wc_price($product->get_price()) . ')' ); } } wp_reset_postdata(); } wp_send_json(array('results' => $products)); } /** * Ajax搜索用户 * * @since 1.0.0 */ public function ajax_search_users() { // 检查安全性 check_ajax_referer('bdfg-admin-nonce', 'nonce'); // 检查权限 if (!current_user_can('manage_woocommerce')) { wp_die(-1); } $term = isset($_GET['term']) ? sanitize_text_field($_GET['term']) : ''; if (empty($term)) { wp_die(); } $args = array( 'search' => '*' . $term . '*', 'search_columns' => array('user_login', 'user_email', 'display_name'), 'number' => 25 ); $user_query = new WP_User_Query($args); $users = array(); if (!empty($user_query->results)) { foreach ($user_query->results as $user) { $users[] = array( 'id' => $user->ID, 'text' => sprintf('%s (%s)', $user->display_name, $user->user_email) ); } } wp_send_json(array('results' => $users)); } /** * 获取应用于测试的规则 * * @since 2.0.0 * @param WP_User $user * @param WC_Product $product * @param int $quantity * @return array */ private function get_eligible_rules_for_test($user, $product, $quantity) { $result = array(); // 详细实现逻辑与calculate_user_discount类似 // 此处省略... return $result; } } /** * 全局方法:检查BDFG角色折扣是否适用于用户 * * @since 2.5.0 * @param int $user_id 用户ID * @return bool */ function bdfg_is_role_discount_applicable($user_id) { $instance = BDFG_Role_Discounts::get_instance(); $settings = get_option('bdfg_role_discounts_settings', array()); // 检查用户是否在排除列表中 if (!empty($settings['excluded_users']) && in_array($user_id, $settings['excluded_users'])) { return false; } // 获取用户角色 $user = get_userdata($user_id); if (!$user) { return false; } $user_roles = $user->roles; // 检查是否有适用的规则 if (!empty($settings['rules']) && is_array($settings['rules'])) { foreach ($settings['rules'] as $rule) { if (empty($rule['enabled'])) { continue; } // 检查用户角色是否匹配 foreach ($user_roles as $role) { if (in_array($role, (array) $rule['roles'])) { return true; } } } } return false; } /** * 全局方法:获取用户角色折扣信息 * * @since 2.5.0 * @param int $user_id 用户ID * @return array|bool */ function bdfg_get_role_discount_info($user_id) { $instance = BDFG_Role_Discounts::get_instance(); $discount_info = false; $user = get_userdata($user_id); if (!$user) { return false; } // 获取所有折扣规则 $settings = get_option('bdfg_role_discounts_settings', array()); // 检查用户是否在排除列表中 if (!empty($settings['excluded_users']) && in_array($user_id, $settings['excluded_users'])) { return false; } // 获取用户角色 $user_roles = $user->roles; $applicable_rules = array(); // 查找适用的规则 if (!empty($settings['rules']) && is_array($settings['rules'])) { foreach ($settings['rules'] as $rule_id => $rule) { if (empty($rule['enabled'])) { continue; } // 检查用户角色是否匹配 $role_match = false; foreach ($user_roles as $role) { if (in_array($role, (array) $rule['roles'])) { $role_match = true; break; } } if ($role_match) { $applicable_rules[$rule_id] = $rule; } } } // 返回适用规则信息 if (!empty($applicable_rules)) { $roles = array(); $discount_percentages = array(); $discount_fixed_amounts = array(); foreach ($applicable_rules as $rule_id => $rule) { if ($rule['discount_type'] === 'percentage') { $discount_percentages[] = floatval($rule['discount_amount']); } else { $discount_fixed_amounts[] = floatval($rule['discount_amount']); } // 收集适用的角色 foreach ((array) $rule['roles'] as $role_id) { if (in_array($role_id, $user_roles)) { $roles[] = $role_id; } } } // 过滤重复的角色 $roles = array_unique($roles); // 获取最高折扣 $max_percentage = !empty($discount_percentages) ? max($discount_percentages) : 0; $max_fixed = !empty($discount_fixed_amounts) ? max($discount_fixed_amounts) : 0; // 创建折扣信息 $discount_info = array( 'has_discount' => true, 'roles' => $roles, 'applicable_rules' => array_keys($applicable_rules), 'max_percentage' => $max_percentage, 'max_fixed_amount' => $max_fixed ); } return $discount_info; } // 启动插件 add_action('plugins_loaded', function() { BDFG_Role_Discounts::get_instance(); }); }
includes/class-bdfg-admin.php
<?php /** * BDFG角色折扣管理面板功能 * * @package BDFG_Role_Discounts * @since 2.5.0 * @author Bei Duo Feng Ou <[email protected]> */ // 如果直接访问此文件,则中止执行 if (!defined('ABSPATH')) { exit; } if (!class_exists('BDFG_Role_Discounts_Admin')) { /** * 管理面板控制类 */ class BDFG_Role_Discounts_Admin { /** * BDFG插件实例 * * @var BDFG_Role_Discounts */ private $plugin; /** * 初始化管理面板功能 * * @param BDFG_Role_Discounts $plugin 插件主实例 */ public function __construct($plugin) { $this->plugin = $plugin; // 添加设置链接 add_filter('plugin_action_links_' . plugin_basename(BDFG_ROLE_DISCOUNTS_FILE), array($this, 'add_settings_link')); // 添加插件元数据 add_filter('plugin_row_meta', array($this, 'plugin_row_meta'), 10, 2); // 添加管理面板通知 add_action('admin_notices', array($this, 'admin_notices')); // 添加帮助标签 add_action('admin_head', array($this, 'add_help_tabs'), 10); } /** * 添加设置链接到插件列表 * * @param array $links 已有链接数组 * @return array 修改后的链接数组 */ public function add_settings_link($links) { $settings_link = '<a href="admin.php?page=bdfg-role-discounts">' . __('设置', 'bdfg-role-discounts') . '</a>'; array_unshift($links, $settings_link); return $links; } /** * 添加额外插件元信息 * * @param array $links 已有链接数组 * @param string $file 当前插件文件 * @return array 修改后的链接数组 */ public function plugin_row_meta($links, $file) { if (plugin_basename(BDFG_ROLE_DISCOUNTS_FILE) === $file) { $row_meta = array( 'docs' => '<a href="' . esc_url('https://beiduofengou.net/plugins/bdfg-role-discounts/docs') . '" target="_blank">' . esc_html__('文档', 'bdfg-role-discounts') . '</a>', 'support' => '<a href="' . esc_url('https://beiduofengou.net/support') . '" target="_blank">' . esc_html__('获取支持', 'bdfg-role-discounts') . '</a>', ); return array_merge($links, $row_meta); } return $links; } /** * 添加管理通知 */ public function admin_notices() { // 检查是否在插件设置页面 $screen = get_current_screen(); if ($screen->id != 'woocommerce_page_bdfg-role-discounts') { return; } // 检查WooCommerce版本是否受支持 if (defined('WC_VERSION') && version_compare(WC_VERSION, '5.0', '<')) { ?> <div class="notice notice-warning"> <p><?php _e('您正在使用较旧版本的WooCommerce。BDFG角色折扣插件可能无法在WooCommerce 5.0以下版本上正常工作。', 'bdfg-role-discounts'); ?></p> </div> <?php } // 检查是否已配置任何折扣规则 $settings = get_option('bdfg_role_discounts_settings', array()); if (empty($settings['rules'])) { ?> <div class="notice notice-info"> <p><?php _e('您尚未创建任何折扣规则。点击"添加规则"按钮开始创建您的第一条角色折扣规则。', 'bdfg-role-discounts'); ?></p> </div> <?php } // 更新提示 - 使用transient来控制显示频率 if (!get_transient('bdfg_promotional_notice_dismissed')) { ?> <div class="notice notice-info is-dismissible bdfg-promo-notice"> <p><?php printf(__('感谢使用BDFG角色折扣!访问我们的<a href="%s" target="_blank">官方网站</a>获取更多插件和教程。', 'bdfg-role-discounts'), 'https://beiduofengou.net'); ?></p> </div> <script> jQuery(document).on('click', '.bdfg-promo-notice .notice-dismiss', function(){ jQuery.ajax({ url: ajaxurl, data: { action: 'bdfg_dismiss_promo_notice', nonce: '<?php echo wp_create_nonce('bdfg-dismiss-notice'); ?>' } }); }); </script> <?php } } /** * 添加帮助标签到设置页面 */ public function add_help_tabs() { $screen = get_current_screen(); if ($screen->id != 'woocommerce_page_bdfg-role-discounts') { return; } // 添加设置帮助标签 $screen->add_help_tab(array( 'id' => 'bdfg-basic-help', 'title' => __('基本设置', 'bdfg-role-discounts'), 'content' => '<h2>' . __('基本设置说明', 'bdfg-role-discounts') . '</h2>' . '<p>' . __('BDFG角色折扣允许您为不同的用户角色设置不同的折扣规则。您可以创建百分比折扣或固定金额折扣。', 'bdfg-role-discounts') . '</p>' . '<p>' . __('在"折扣规则"标签中,您可以添加多条折扣规则,每条规则可以应用于不同的用户角色、产品分类或满足特定条件。', 'bdfg-role-discounts') . '</p>' )); // 添加条件帮助标签 $screen->add_help_tab(array( 'id' => 'bdfg-conditions-help', 'title' => __('条件设置', 'bdfg-role-discounts'), 'content' => '<h2>' . __('条件设置说明', 'bdfg-role-discounts') . '</h2>' . '<p>' . __('您可以为每条折扣规则添加多个条件,如星期几、一天中的时间、客户订单数量和客户消费金额等。', 'bdfg-role-discounts') . '</p>' . '<p>' . __('条件关系可以设置为"满足所有条件"(AND)或"满足任一条件"(OR),以实现复杂的折扣逻辑。', 'bdfg-role-discounts') . '</p>' )); // 设置帮助侧栏 $screen->set_help_sidebar( '<p><strong>' . __('更多帮助:', 'bdfg-role-discounts') . '</strong></p>' . '<p><a href="https://beiduofengou.net/plugins/bdfg-role-discounts/docs" target="_blank">' . __('查看完整文档', 'bdfg-role-discounts') . '</a></p>' . '<p><a href="https://beiduofengou.net/support" target="_blank">' . __('获取技术支持', 'bdfg-role-discounts') . '</a></p>' ); } } }
includes/class-bdfg-frontend.php
相关文章: woocommerce产品分析插件
<?php /** * BDFG角色折扣前端功能 * * @package BDFG_Role_Discounts * @since 2.5.0 * @author Bei Duo Feng Ou <[email protected]> */ // 如果直接访问此文件,则中止执行 if (!defined('ABSPATH')) { exit; } if (!class_exists('BDFG_Role_Discounts_Frontend')) { /** * 前端功能控制类 */ class BDFG_Role_Discounts_Frontend { /** * BDFG插件实例 * * @var BDFG_Role_Discounts */ private $plugin; /** * 插件设置 * * @var array */ private $settings; /** * 初始化前端功能 * * @param BDFG_Role_Discounts $plugin 插件主实例 */ public function __construct($plugin) { $this->plugin = $plugin; $this->settings = get_option('bdfg_role_discounts_settings', array()); // 显示折扣信息 add_action('woocommerce_before_add_to_cart_form', array($this, 'display_discount_info')); // 显示原价 add_filter('woocommerce_get_price_html', array($this, 'show_original_price'), 99, 2); // 添加产品折扣徽章 add_action('woocommerce_before_shop_loop_item_title', array($this, 'add_discount_badge'), 10); // 支持嵌入在内容中的折扣信息 add_shortcode('bdfg_discount_info', array($this, 'discount_info_shortcode')); } /** * 在产品页面显示折扣信息 */ public function display_discount_info() { // 如果未启用显示折扣信息,则返回 if (empty($this->settings['show_discount_info'])) { return; } // 获取当前产品 $product = wc_get_product(); if (!$product) { return; } // 获取当前用户 $user_id = get_current_user_id(); if (!$user_id) { return; } $user = get_userdata($user_id); if (!$user) { return; } // 检查用户是否在排除列表中 if (!empty($this->settings['excluded_users']) && in_array($user_id, $this->settings['excluded_users'])) { return; } // 检查产品是否在排除列表中 if (!empty($this->settings['excluded_products']) && in_array($product->get_id(), $this->settings['excluded_products'])) { return; } // 如果设置了排除特价产品,并且产品正在特价中,则返回 if (!empty($this->settings['exclude_sale_items']) && $product->is_on_sale()) { return; } // 获取用户折扣信息 $discount_info = $this->get_user_discount_info($user, $product); // 如果有折扣,显示信息 if ($discount_info && $discount_info['discount_amount'] > 0) { $discount_text = !empty($this->settings['discount_text']) ? $this->settings['discount_text'] : __('您享有 {discount} 的折扣!', 'bdfg-role-discounts'); // 替换变量 $discount_text = str_replace('{discount}', $discount_info['discount_formatted'], $discount_text); $discount_text = str_replace('{role}', $discount_info['role_name'], $discount_text); echo '<div class="bdfg-discount-info">' . esc_html($discount_text) . '</div>'; } } /** * 在产品列表中添加折扣徽章 */ public function add_discount_badge() { global $product; // 如果没有配置显示折扣徽章,则返回 if (empty($this->settings['show_discount_badge'])) { return; } // 获取当前用户 $user_id = get_current_user_id(); if (!$user_id) { return; } // 检查用户是否在排除列表中 if (!empty($this->settings['excluded_users']) && in_array($user_id, $this->settings['excluded_users'])) { return; } // 检查产品是否在排除列表中 if (!empty($this->settings['excluded_products']) && in_array($product->get_id(), $this->settings['excluded_products'])) { return; } // 如果设置了排除特价产品,并且产品正在特价中,则返回 if (!empty($this->settings['exclude_sale_items']) && $product->is_on_sale()) { return; } // 获取用户折扣信息 $user = get_userdata($user_id); if (!$user) { return; } $discount_info = $this->get_user_discount_info($user, $product); // 如果有折扣,显示徽章 if ($discount_info && $discount_info['discount_amount'] > 0) { echo '<span class="bdfg-discount-badge">' . esc_html($discount_info['discount_formatted']) . '</span>'; } } /** * 显示原价在折扣价旁边 * * @param string $price_html 价格HTML * @param WC_Product $product 产品对象 * @return string */ public function show_original_price($price_html, $product) { // 如果未启用显示原价,则返回原始价格HTML if (empty($this->settings['show_original_price'])) { return $price_html; } // 获取当前用户 $user_id = get_current_user_id(); if (!$user_id) { return $price_html; } // 获取用户 $user = get_userdata($user_id); if (!$user) { return $price_html; } // 检查用户是否在排除列表中 if (!empty($this->settings['excluded_users']) && in_array($user_id, $this->settings['excluded_users'])) { return $price_html; } // 检查产品是否在排除列表中 if (!empty($this->settings['excluded_products']) && in_array($product->get_id(), $this->settings['excluded_products'])) { return $price_html; } // 如果设置了排除特价产品,并且产品正在特价中,则返回原始价格HTML if (!empty($this->settings['exclude_sale_items']) && $product->is_on_sale()) { return $price_html; } // 获取用户折扣信息 $discount_info = $this->get_user_discount_info($user, $product); // 如果有折扣,修改价格HTML if ($discount_info && $discount_info['discount_amount'] > 0) { $original_price = $product->get_price(); $discounted_price = $original_price - $discount_info['discount_amount']; if ($discounted_price < 0) { $discounted_price = 0; } $original_price_html = wc_price($original_price); $discounted_price_html = wc_price($discounted_price); $price_html = '<del>' . $original_price_html . '</del> <ins>' . $discounted_price_html . '</ins>'; } return $price_html; } /** * 获取用户折扣信息 * * @param WP_User $user 用户对象 * @param WC_Product $product 产品对象 * @return array|bool 折扣信息或false */ public function get_user_discount_info($user, $product) { if (!$user || !$product) { return false; } // 实现逻辑与主类中的calculate_user_discount类似 // 此处调用插件主实例的方法 return $this->plugin->calculate_user_discount($user, $product); } /** * 折扣信息短代码 * * @param array $atts 短代码属性 * @return string */ public function discount_info_shortcode($atts) { $atts = shortcode_atts(array( 'product_id' => 0, 'custom_text' => '', ), $atts, 'bdfg_discount_info'); // 获取产品ID $product_id = intval($atts['product_id']); if (!$product_id) { // 如果没有指定产品ID,则使用当前产品 global $product; if (!$product) { return ''; } $product_id = $product->get_id(); } else { $product = wc_get_product($product_id); if (!$product) { return ''; } } // 获取当前用户 $user_id = get_current_user_id(); if (!$user_id) { return ''; } $user = get_userdata($user_id); if (!$user) { return ''; } // 检查用户是否在排除列表中 if (!empty($this->settings['excluded_users']) && in_array($user_id, $this->settings['excluded_users'])) { return ''; } // 检查产品是否在排除列表中 if (!empty($this->settings['excluded_products']) && in_array($product_id, $this->settings['excluded_products'])) { return ''; } // 如果设置了排除特价产品,并且产品正在特价中,则返回 if (!empty($this->settings['exclude_sale_items']) && $product->is_on_sale()) { return ''; } // 获取用户折扣信息 $discount_info = $this->get_user_discount_info($user, $product); // 如果有折扣,显示信息 if ($discount_info && $discount_info['discount_amount'] > 0) { $discount_text = !empty($atts['custom_text']) ? $atts['custom_text'] : (!empty($this->settings['discount_text']) ? $this->settings['discount_text'] : __('您享有 {discount} 的折扣!', 'bdfg-role-discounts')); // 替换变量 $discount_text = str_replace('{discount}', $discount_info['discount_formatted'], $discount_text); $discount_text = str_replace('{role}', $discount_info['role_name'], $discount_text); $discount_text = str_replace('{product}', $product->get_name(), $discount_text); return '<div class="bdfg-discount-info">' . esc_html($discount_text) . '</div>'; } return ''; } } }
assets/css/admin.css
/** * BDFG Role-Based Discounts for WooCommerce - Admin Styles * * @package BDFG_Role_Discounts * @author Bei Duo Feng Ou * @version 2.6.0 * @updated 2025-03-06 */ /* 主要容器样式 */ .bdfg-role-discounts { margin: 20px 0; max-width: 1300px; } .bdfg-header-banner { background: #f9f9f9; border: 1px solid #e5e5e5; padding: 10px 15px; margin-bottom: 20px; display: flex; justify-content: flex-end; align-items: center; } .bdfg-version { margin-right: 15px; color: #666; font-style: italic; } .bdfg-docs-link, .bdfg-support-link { margin-left: 15px; text-decoration: none; } /* 标签导航 */ .bdfg-tabs { margin-bottom: 20px; } .bdfg-tabs-nav { display: flex; margin: 0; padding: 0; list-style-type: none; border-bottom: 1px solid #ccc; } .bdfg-tabs-nav li { margin: 0; padding: 0; } .bdfg-tabs-nav a { display: block; padding: 10px 15px; text-decoration: none; background: #f1f1f1; border: 1px solid #ccc; border-bottom: none; margin-right: 5px; border-radius: 3px 3px 0 0; color: #555; font-weight: bold; } .bdfg-tabs-nav li.active a { background: #fff; border-bottom: 1px solid #fff; margin-bottom: -1px; color: #0073aa; } .bdfg-tab-content { background: #fff; padding: 20px; border: 1px solid #ccc; border-top: none; } .bdfg-tab-pane { display: none; } .bdfg-tab-pane.active { display: block; } /* 规则容器 */ .bdfg-rules-container { margin-top: 15px; } .bdfg-rule-row { background: #fff; border: 1px solid #ccc; margin-bottom: 15px; border-radius: 3px; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); } .bdfg-rule-header { padding: 10px 15px; background: #f7f7f7; border-bottom: 1px solid #eee; display: flex; justify-content: space-between; align-items: center; cursor: pointer; } .bdfg-rule-title { display: flex; align-items: center; font-weight: bold; } .bdfg-drag-handle { cursor: move; margin-right: 10px; color: #bbb; } .bdfg-rule-row:hover .bdfg-drag-handle { color: #888; } .bdfg-rule-actions { display: flex; align-items: center; } .bdfg-rule-actions a { margin-left: 10px; text-decoration: none; color: #555; } .bdfg-rule-content { padding: 15px; display: none; } /* 开关按钮 */ .bdfg-toggle { position: relative; display: inline-block; width: 40px; height: 20px; } .bdfg-toggle input { opacity: 0; width: 0; height: 0; } .bdfg-toggle-slider { position: absolute; cursor: pointer; top: 0; left: 0; right: 0; bottom: 0; background-color: #ccc; transition: .4s; border-radius: 34px; } .bdfg-toggle-slider:before { position: absolute; content: ""; height: 16px; width: 16px; left: 2px; bottom: 2px; background-color: white; transition: .4s; border-radius: 50%; } .bdfg-toggle input:checked + .bdfg-toggle-slider { background-color: #2196F3; } .bdfg-toggle input:checked + .bdfg-toggle-slider:before { transform: translateX(20px); } /* 条件行 */ .bdfg-condition-row { display: flex; align-items: center; margin-bottom: 10px; padding: 10px; background: #f9f9f9; border: 1px solid #eee; border-radius: 3px; } .bdfg-condition-row select, .bdfg-condition-row input { margin-right: 10px; } .bdfg-additional-conditions { margin-bottom: 10px; } /* 日期范围字段 */ .date-range-fields { display: flex; gap: 10px; } .bdfg-datepicker { width: 120px; } /* 工具部分 */ .bdfg-tools-section { margin-bottom: 30px; padding-bottom: 20px; border-bottom: 1px solid #eee; } .bdfg-tools-section:last-child { border-bottom: none; } .bdfg-test-output { padding: 15px; background: #f9f9f9; border: 1px solid #eee; margin-top: 10px; max-height: 400px; overflow-y: auto; } #export-data, #import-data { font-family: monospace; font-size: 12px; } /* 其他样式 */ .description { font-style: italic; color: #666; }
assets/css/frontend.css
相关文章: WooCommerce 预定功能插件
/** * BDFG Role-Based Discounts for WooCommerce - Frontend Styles * * @package BDFG_Role_Discounts * @author Bei Duo Feng Ou * @version 2.6.0 * @updated 2025-03-06 */ /* 折扣信息 */ .bdfg-discount-info { padding: 10px 15px; background-color: #f7f6f7; border-left: 4px solid #2196F3; margin-bottom: 20px; font-size: 0.95em; color: #515151; box-shadow: 0 1px 3px rgba(0,0,0,0.05); position: relative; display: inline-block; width: 100%; box-sizing: border-box; } /* 折扣价格 */ .price del { opacity: 0.7; font-size: 0.9em; text-decoration: line-through; margin-right: 0.5em; } .price ins { font-weight: 700; text-decoration: none; color: #2196F3; } /* 折扣徽章 */ .bdfg-discount-badge { position: absolute; top: 0; right: 0; background: #2196F3; color: white; padding: 5px 10px; font-size: 0.8em; font-weight: bold; z-index: 9; border-radius: 0 0 0 5px; } /* 响应式样式 */ @media screen and (max-width: 768px) { .bdfg-discount-info { padding: 8px 12px; font-size: 0.9em; } .bdfg-discount-badge { padding: 3px 8px; font-size: 0.75em; } }
assets/js/admin.js
/** * BDFG Role-Based Discounts for WooCommerce - Admin JavaScript * * @package BDFG_Role_Discounts * @author Bei Duo Feng Ou * @version 2.6.0 * @updated 2025-03-06 16:02:29 */ (function($) { 'use strict'; // DOM ready $(function() { // 初始化标签切换 initTabs(); // 初始化规则折叠 initRuleCollapse(); // 初始化拖拽排序 initRuleSorting(); // 初始化规则操作 initRuleActions(); // 初始化折扣类型切换 initDiscountTypeToggle(); // 初始化条件类型切换 initConditionTypeToggle(); // 初始化日期选择器 initDatepickers(); // 初始化选择框 initSelect2(); // 初始化测试功能 initTestDiscount(); // 初始化导入导出功能 initImportExport(); // 初始化首次购买重置功能 initResetFirstPurchase(); }); // 初始化标签切换 function initTabs() { $('.bdfg-tabs-nav a').on('click', function(e) { e.preventDefault(); var target = $(this).attr('href'); // 更新活动标签 $('.bdfg-tabs-nav li').removeClass('active'); $(this).parent().addClass('active'); // 显示目标面板 $('.bdfg-tab-pane').removeClass('active'); $(target).addClass('active'); // 保存当前活动标签到本地存储 if (typeof localStorage !== 'undefined') { localStorage.setItem('bdfg_active_tab', target); } }); // 从本地存储恢复上次活动的标签 if (typeof localStorage !== 'undefined') { var activeTab = localStorage.getItem('bdfg_active_tab'); if (activeTab && $(activeTab).length) { $('.bdfg-tabs-nav a[href="' + activeTab + '"]').click(); } } } // 初始化规则折叠 function initRuleCollapse() { // 点击规则标题切换内容显示 $('.bdfg-rule-header').on('click', function(e) { if (!$(e.target).is('.bdfg-toggle, .bdfg-toggle-slider, .bdfg-delete-rule, .bdfg-drag-handle')) { var $content = $(this).next('.bdfg-rule-content'); var $icon = $(this).find('.bdfg-toggle-rule'); $content.slideToggle(200); if ($content.is(':visible')) { $icon.removeClass('dashicons-arrow-down-alt2').addClass('dashicons-arrow-up-alt2'); } else { $icon.removeClass('dashicons-arrow-up-alt2').addClass('dashicons-arrow-down-alt2'); } } }); // 单独点击切换图标也切换规则内容 $('.bdfg-toggle-rule').on('click', function(e) { e.preventDefault(); e.stopPropagation(); var $header = $(this).closest('.bdfg-rule-header'); $header.trigger('click'); }); } // 初始化拖拽排序 function initRuleSorting() { $('.bdfg-rules-container').sortable({ handle: '.bdfg-drag-handle', items: '.bdfg-rule-row:not(.rule-template)', axis: 'y', opacity: 0.7, cursor: 'move', update: function() { // 可以在这里添加规则排序更新逻辑 } }); } // 初始化规则操作 function initRuleActions() { // 添加规则按钮 $('.add-rule').on('click', function() { var $template = $('.rule-template'); var $newRule = $template.clone(); var ruleId = 'rule_' + new Date().getTime(); $newRule.removeClass('rule-template').removeAttr('style'); $newRule.attr('data-rule-id', ruleId); // 更新新规则中的所有表单字段名称 $newRule.find('[name]').each(function() { var name = $(this).attr('name'); name = name.replace('RULE_ID', ruleId); $(this).attr('name', name); }); $newRule.find('.condition-template').remove(); $template.before($newRule); // 初始化新规则中的各种控件 initRuleControls($newRule); // 显示新规则的内容 $newRule.find('.bdfg-rule-content').show(); $newRule.find('.bdfg-toggle-rule') .removeClass('dashicons-arrow-down-alt2') .addClass('dashicons-arrow-up-alt2'); }); // 删除规则按钮 $(document).on('click', '.bdfg-delete-rule', function(e) { e.preventDefault(); e.stopPropagation(); if (confirm(bdfg_params.i18n.confirm_delete)) { $(this).closest('.bdfg-rule-row').remove(); } }); // 规则名称与标题同步 $(document).on('input', '.rule-name-input', function() { var name = $(this).val() || bdfg_params.i18n.unnamed_rule; $(this).closest('.bdfg-rule-row').find('.rule-name').text(name); }); // 添加条件按钮 $(document).on('click', '.add-condition', function() { var $btn = $(this); var prefix = $btn.data('prefix'); var $template = $btn.closest('tr').find('.condition-template'); var $newCondition = $template.children().clone(); var conditionId = 'condition_' + new Date().getTime(); $newCondition.attr('data-condition-id', conditionId); // 更新新条件中的所有表单字段名称 $newCondition.find('[name]').each(function() { var name = $(this).attr('name'); name = name.replace('CONDITION_ID', conditionId); $(this).attr('name', name); }); $btn.closest('tr').find('.bdfg-additional-conditions').append($newCondition); // 初始化新条件中的控件 initConditionControls($newCondition); }); // 删除条件按钮 $(document).on('click', '.delete-condition', function() { $(this).closest('.bdfg-condition-row').remove(); }); } // 初始化规则中的控件 function initRuleControls($rule) { $rule.find('.bdfg-multiselect').select2(); $rule.find('.bdfg-datepicker').datepicker({ dateFormat: bdfg_params.date_format, changeMonth: true, changeYear: true }); initDiscountTypeToggle($rule); initConditionTypeToggle($rule); } // 初始化条件中的控件 function initConditionControls($condition) { // 条件类型切换 $condition.find('.condition-type').trigger('change'); } // 初始化折扣类型切换 function initDiscountTypeToggle($context) { var $container = $context || $(document); // 初始化已有的折扣类型选择 $container.find('.discount-type-select').each(function() { updateDiscountFields($(this)); }); // 折扣类型变更时更新字段 $container.on('change', '.discount-type-select', function() { updateDiscountFields($(this)); }); function updateDiscountFields($select) { var type = $select.val(); var $row = $select.closest('tr'); var $nextRow = $row.next('tr'); var $discountField = $nextRow.find('.discount-amount-field'); if (type === 'percentage') { $discountField.find('.discount-percentage').show(); $discountField.find('.discount-fixed').hide(); } else { $discountField.find('.discount-percentage').hide(); $discountField.find('.discount-fixed').show(); } } } // 初始化条件类型切换 function initConditionTypeToggle($context) { var $container = $context || $(document); // 初始化已有的条件类型选择 $container.find('.condition-type').each(function() { updateConditionFields($(this)); }); // 条件类型变更时更新字段 $container.on('change', '.condition-type', function() { updateConditionFields($(this)); }); function updateConditionFields($select) { var type = $select.val(); var $row = $select.closest('.bdfg-condition-row'); var $valueFields = $row.find('.condition-value-field > div'); var $operators = $row.find('.condition-operator option'); // 隐藏所有值字段 $valueFields.hide(); // 根据条件类型显示相应的值字段 if (type === 'day_of_week') { $row.find('.condition-day-of-week').show(); // 启用/禁用操作符 $operators.prop('disabled', false); $operators.filter(function() { return ['greater_than', 'less_than', 'contains'].indexOf($(this).val()) !== -1; }).prop('disabled', true); } else if (type === 'time_of_day') { $row.find('.condition-time-of-day').show(); // 启用所有操作符 $operators.prop('disabled', false); $operators.filter(function() { return ['contains'].indexOf($(this).val()) !== -1; }).prop('disabled', true); } else if (type === 'customer_order_count' || type === 'customer_spent_amount') { $row.find('.condition-numeric').show(); // 启用所有操作符 $operators.prop('disabled', false); $operators.filter(function() { return ['contains'].indexOf($(this).val()) !== -1; }).prop('disabled', true); } // 如果当前选中的操作符被禁用,则重置为第一个可用操作符 var $currentOperator = $row.find('.condition-operator option:selected'); if ($currentOperator.prop('disabled')) { $row.find('.condition-operator option:not(:disabled)').first().prop('selected', true); } } } // 初始化日期选择器 function initDatepickers() { $('.bdfg-datepicker').datepicker({ dateFormat: bdfg_params.date_format, changeMonth: true, changeYear: true }); } // 初始化Select2 function initSelect2() { // 多选框使用Select2 $('.bdfg-multiselect').select2(); // 产品选择器 $('.bdfg-product-select').select2({ ajax: { url: bdfg_params.ajax_url, dataType: 'json', delay: 250, data: function(params) { return { term: params.term, action: 'bdfg_search_products', nonce: bdfg_params.nonce }; }, processResults: function(data) { return { results: data.results }; }, cache: true }, minimumInputLength: 3, placeholder: bdfg_params.i18n.search_products }); // 用户选择器 $('.bdfg-user-select').select2({ ajax: { url: bdfg_params.ajax_url, dataType: 'json', delay: 250, data: function(params) { return { term: params.term, action: 'bdfg_search_users', nonce: bdfg_params.nonce }; }, processResults: function(data) { return { results: data.results }; }, cache: true }, minimumInputLength: 3, placeholder: bdfg_params.i18n.search_users }); } // 初始化测试折扣功能 function initTestDiscount() { $('#run-test').on('click', function() { var $btn = $(this); var userId = $('#test-user').val(); var productId = $('#test-product').val(); var quantity = $('#test-quantity').val(); if (!userId || !productId) { alert(bdfg_params.i18n.select_user_product); return; } // 显示加载状态 $btn.prop('disabled', true).text('测试中...'); $('#test-results').hide(); // 发送Ajax请求 $.ajax({ url: bdfg_params.ajax_url, type: 'POST', data: { action: 'bdfg_test_discount_rule', nonce: bdfg_params.nonce, user_id: userId, product_id: productId, quantity: quantity }, success: function(response) { // 恢复按钮状态 $btn.prop('disabled', false).text('测试折扣'); if (response.success) { // 格式化测试结果 var html = '<div class="bdfg-test-result">'; // 基本信息 html += '<h4>基本信息</h4>'; html += '<table class="widefat" cellspacing="0">'; html += '<tr><td>测试时间:</td><td>' + response.timestamp + '</td></tr>'; html += '<tr><td>用户:</td><td>' + response.user.name + ' (' + response.user.login + ')</td></tr>'; html += '<tr><td>用户角色:</td><td>' + response.user.roles + '</td></tr>'; html += '<tr><td>产品:</td><td>' + response.product.name + ' (#' + response.product.id + ')</td></tr>'; html += '<tr><td>原价:</td><td>' + response.product.original_price_formatted + '</td></tr>'; html += '<tr><td>数量:</td><td>' + response.product.quantity + '</td></tr>'; html += '</table>'; // 折扣结果 html += '<h4>折扣结果</h4>'; html += '<table class="widefat" cellspacing="0">'; if (response.discount.applied) { html += '<tr><td>应用折扣:</td><td><span style="color:green">是</span></td></tr>'; html += '<tr><td>折扣金额:</td><td>' + response.discount.discount_amount_formatted + ' (' + response.discount.discount_percentage + ')</td></tr>'; html += '<tr><td>折扣后价格:</td><td>' + response.discount.discounted_price_formatted + '</td></tr>'; } else { html += '<tr><td>应用折扣:</td><td><span style="color:red">否</span></td></tr>'; html += '<tr><td colspan="2">没有找到适用的折扣规则</td></tr>'; } html += '</table>'; // 规则评估结果 if (response.rules && response.rules.length > 0) { html += '<h4>规则评估</h4>'; html += '<table class="widefat" cellspacing="0">'; html += '<thead><tr><th>规则名称</th><th>是否适用</th><th>折扣金额</th><th>状态</th></tr></thead>'; html += '<tbody>'; $.each(response.rules, function(index, rule) { html += '<tr>'; html += '<td>' + rule.name + '</td>'; if (rule.is_eligible) { html += '<td><span style="color:green">是</span></td>'; html += '<td>' + rule.calculated_discount_formatted + '</td>'; if (rule.is_best_discount) { html += '<td><strong style="color:green">已应用 (最佳折扣)</strong></td>'; } else { html += '<td>合格但未应用</td>'; } } else { html += '<td><span style="color:red">否</span></td>'; html += '<td>0</td>'; html += '<td>' + rule.not_eligible_reason + '</td>'; } html += '</tr>'; }); html += '</tbody>'; html += '</table>'; } html += '</div>'; // 显示结果 $('#test-results').show().find('.bdfg-test-output').html(html); } else { alert(response.data.message || '测试折扣失败'); } }, error: function() { $btn.prop('disabled', false).text('测试折扣'); alert('发生错误,请重试'); } }); }); } // 初始化导入导出功能 function initImportExport() { // 导出设置 $('#export-settings').on('click', function() { var $btn = $(this); var $container = $('#export-container'); $btn.prop('disabled', true).text('导出中...'); $.ajax({ url: bdfg_params.ajax_url, type: 'POST', data: { action: 'bdfg_export_settings', nonce: bdfg_params.nonce }, success: function(response) { $btn.prop('disabled', false).text('导出设置'); if (response.success) { $('#export-data').val(response.data.data); $container.slideDown(); } else { alert(response.data.message || '导出设置失败'); } }, error: function() { $btn.prop('disabled', false).text('导出设置'); alert('发生错误,请重试'); } }); }); // 复制导出数据到剪贴板 $('#copy-export').on('click', function() { var exportData = $('#export-data'); exportData.select(); try { var successful = document.execCommand('copy'); if (successful) { alert(bdfg_params.i18n.copied); } else { alert(bdfg_params.i18n.copy_failed); } } catch (err) { alert(bdfg_params.i18n.copy_failed); } }); // 导入设置 $('#import-settings').on('click', function() { var $btn = $(this); var importData = $('#import-data').val(); if (!importData) { alert('请先粘贴要导入的设置数据'); return; } if (!confirm(bdfg_params.i18n.confirm_import)) { return; } $btn.prop('disabled', true).text('导入中...'); $.ajax({ url: bdfg_params.ajax_url, type: 'POST', data: { action: 'bdfg_import_settings', nonce: bdfg_params.nonce, import_data: importData }, success: function(response) { $btn.prop('disabled', false).text('导入设置'); if (response.success) { alert(bdfg_params.i18n.import_success); window.location.reload(); } else { alert(response.data.message || bdfg_params.i18n.import_error); } }, error: function() { $btn.prop('disabled', false).text('导入设置'); alert('发生错误,请重试'); } }); }); } // 初始化首次购买重置功能 function initResetFirstPurchase() { $('#reset-first-purchase').on('click', function() { var $btn = $(this); if (!confirm(bdfg_params.i18n.confirm_reset)) { return; } $btn.prop('disabled', true).text('重置中...'); $.ajax({ url: bdfg_params.ajax_url, type: 'POST', data: { action: 'bdfg_reset_first_purchase', nonce: bdfg_params.nonce }, success: function(response) { $btn.prop('disabled', false).text('重置所有首次购买记录'); if (response.success) { alert(bdfg_params.i18n.reset_success); } else { alert(response.data.message || '重置失败'); } }, error: function() { $btn.prop('disabled', false).text('重置所有首次购买记录'); alert('发生错误,请重试'); } }); }); } })(jQuery);