318 lines
9.9 KiB
PHP
318 lines
9.9 KiB
PHP
<?php
|
||
/**
|
||
* 混装产品前端展示类
|
||
*
|
||
* 处理混装产品的前端显示和用户交互
|
||
*/
|
||
|
||
if (!defined('ABSPATH')) {
|
||
exit;
|
||
}
|
||
|
||
/**
|
||
* 混装产品前端展示类
|
||
*/
|
||
class Yoone_Bundle_Frontend {
|
||
|
||
/**
|
||
* 构造函数
|
||
*/
|
||
public function __construct() {
|
||
$this->init_hooks();
|
||
}
|
||
|
||
/**
|
||
* 初始化钩子
|
||
*/
|
||
private function init_hooks() {
|
||
// 在产品页面显示混装选项
|
||
add_action('woocommerce_single_product_summary', array($this, 'display_bundle_options'), 25);
|
||
|
||
// 处理混装产品添加到购物车
|
||
add_filter('woocommerce_add_to_cart_validation', array($this, 'validate_bundle_add_to_cart'), 10, 3);
|
||
add_action('woocommerce_add_to_cart', array($this, 'add_bundle_to_cart'), 10, 6);
|
||
|
||
// 在购物车中显示混装信息
|
||
add_filter('woocommerce_get_item_data', array($this, 'display_bundle_cart_item_data'), 10, 2);
|
||
|
||
// 计算混装价格
|
||
add_action('woocommerce_before_calculate_totals', array($this, 'calculate_bundle_cart_item_price'));
|
||
|
||
// 加载前端脚本和样式
|
||
add_action('wp_enqueue_scripts', array($this, 'enqueue_scripts'));
|
||
}
|
||
|
||
/**
|
||
* 显示混装选项
|
||
*/
|
||
public function display_bundle_options() {
|
||
global $product;
|
||
|
||
if (!$product || !$this->is_bundle_product($product->get_id())) {
|
||
return;
|
||
}
|
||
|
||
$bundle = $this->get_product_bundle($product->get_id());
|
||
if (!$bundle || !$bundle->is_available()) {
|
||
return;
|
||
}
|
||
|
||
$items = $bundle->get_items();
|
||
if (empty($items)) {
|
||
return;
|
||
}
|
||
|
||
// 加载模板
|
||
wc_get_template(
|
||
'single-product/bundle-options.php',
|
||
array(
|
||
'bundle' => $bundle,
|
||
'items' => $items,
|
||
'product' => $product
|
||
),
|
||
'',
|
||
YOONE_SUBSCRIPTIONS_PLUGIN_PATH . 'templates/frontend/'
|
||
);
|
||
}
|
||
|
||
/**
|
||
* 验证混装产品添加到购物车
|
||
*/
|
||
public function validate_bundle_add_to_cart($passed, $product_id, $quantity) {
|
||
if (!$this->is_bundle_product($product_id)) {
|
||
return $passed;
|
||
}
|
||
|
||
$bundle = $this->get_product_bundle($product_id);
|
||
if (!$bundle) {
|
||
wc_add_notice(__('混装产品不存在', 'yoone-subscriptions'), 'error');
|
||
return false;
|
||
}
|
||
|
||
// 验证数量
|
||
if (!$bundle->validate_quantity($quantity)) {
|
||
$min = $bundle->get_min_quantity();
|
||
$max = $bundle->get_max_quantity();
|
||
|
||
if ($max) {
|
||
$message = sprintf(__('数量必须在 %d 到 %d 之间', 'yoone-subscriptions'), $min, $max);
|
||
} else {
|
||
$message = sprintf(__('最小数量为 %d', 'yoone-subscriptions'), $min);
|
||
}
|
||
|
||
wc_add_notice($message, 'error');
|
||
return false;
|
||
}
|
||
|
||
// 验证选择的商品
|
||
$selected_items = isset($_POST['bundle_items']) ? $_POST['bundle_items'] : array();
|
||
if (empty($selected_items)) {
|
||
wc_add_notice(__('请选择混装商品', 'yoone-subscriptions'), 'error');
|
||
return false;
|
||
}
|
||
|
||
// 验证必需商品
|
||
$bundle_items = $bundle->get_items();
|
||
foreach ($bundle_items as $item) {
|
||
if ($item['is_required'] && !isset($selected_items[$item['product_id']])) {
|
||
$product = wc_get_product($item['product_id']);
|
||
$message = sprintf(__('必须选择商品: %s', 'yoone-subscriptions'), $product->get_name());
|
||
wc_add_notice($message, 'error');
|
||
return false;
|
||
}
|
||
}
|
||
|
||
// 验证库存
|
||
foreach ($selected_items as $item_product_id => $item_quantity) {
|
||
$item_product = wc_get_product($item_product_id);
|
||
if (!$item_product) {
|
||
continue;
|
||
}
|
||
|
||
if (!$item_product->has_enough_stock($item_quantity * $quantity)) {
|
||
$message = sprintf(__('商品 %s 库存不足', 'yoone-subscriptions'), $item_product->get_name());
|
||
wc_add_notice($message, 'error');
|
||
return false;
|
||
}
|
||
}
|
||
|
||
return $passed;
|
||
}
|
||
|
||
/**
|
||
* 添加混装产品到购物车
|
||
*/
|
||
public function add_bundle_to_cart($cart_item_key, $product_id, $quantity, $variation_id, $variation, $cart_item_data) {
|
||
if (!$this->is_bundle_product($product_id)) {
|
||
return;
|
||
}
|
||
|
||
$selected_items = isset($_POST['bundle_items']) ? $_POST['bundle_items'] : array();
|
||
if (empty($selected_items)) {
|
||
return;
|
||
}
|
||
|
||
// 保存混装信息到购物车项目
|
||
WC()->cart->cart_contents[$cart_item_key]['bundle_items'] = $selected_items;
|
||
WC()->cart->cart_contents[$cart_item_key]['is_bundle'] = true;
|
||
}
|
||
|
||
/**
|
||
* 在购物车中显示混装信息
|
||
*/
|
||
public function display_bundle_cart_item_data($item_data, $cart_item) {
|
||
if (!isset($cart_item['is_bundle']) || !$cart_item['is_bundle']) {
|
||
return $item_data;
|
||
}
|
||
|
||
if (!isset($cart_item['bundle_items']) || empty($cart_item['bundle_items'])) {
|
||
return $item_data;
|
||
}
|
||
|
||
$item_data[] = array(
|
||
'key' => __('混装商品', 'yoone-subscriptions'),
|
||
'value' => $this->format_bundle_items($cart_item['bundle_items'])
|
||
);
|
||
|
||
return $item_data;
|
||
}
|
||
|
||
/**
|
||
* 计算混装购物车项目价格
|
||
*/
|
||
public function calculate_bundle_cart_item_price($cart) {
|
||
if (is_admin() && !defined('DOING_AJAX')) {
|
||
return;
|
||
}
|
||
|
||
foreach ($cart->get_cart() as $cart_item_key => $cart_item) {
|
||
if (!isset($cart_item['is_bundle']) || !$cart_item['is_bundle']) {
|
||
continue;
|
||
}
|
||
|
||
$product_id = $cart_item['product_id'];
|
||
$bundle = $this->get_product_bundle($product_id);
|
||
|
||
if (!$bundle) {
|
||
continue;
|
||
}
|
||
|
||
$selected_items = isset($cart_item['bundle_items']) ? $cart_item['bundle_items'] : array();
|
||
$bundle_price = $bundle->calculate_price($this->format_selected_items($selected_items));
|
||
|
||
// 设置新价格
|
||
$cart_item['data']->set_price($bundle_price);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 加载前端脚本和样式
|
||
*/
|
||
public function enqueue_scripts() {
|
||
if (is_product()) {
|
||
wp_enqueue_script(
|
||
'yoone-bundle-frontend',
|
||
YOONE_SUBSCRIPTIONS_PLUGIN_URL . 'assets/js/bundle-frontend.js',
|
||
array('jquery'),
|
||
YOONE_SUBSCRIPTIONS_VERSION,
|
||
true
|
||
);
|
||
|
||
wp_enqueue_style(
|
||
'yoone-bundle-frontend',
|
||
YOONE_SUBSCRIPTIONS_PLUGIN_URL . 'assets/css/bundle-frontend.css',
|
||
array(),
|
||
YOONE_SUBSCRIPTIONS_VERSION
|
||
);
|
||
|
||
// 本地化脚本
|
||
wp_localize_script('yoone-bundle-frontend', 'yoone_bundle_params', array(
|
||
'ajax_url' => admin_url('admin-ajax.php'),
|
||
'nonce' => wp_create_nonce('yoone_bundle_nonce'),
|
||
'i18n' => array(
|
||
'select_items' => __('请选择商品', 'yoone-subscriptions'),
|
||
'calculating' => __('计算中...', 'yoone-subscriptions'),
|
||
'error' => __('发生错误', 'yoone-subscriptions')
|
||
)
|
||
));
|
||
}
|
||
}
|
||
|
||
/*
|
||
|--------------------------------------------------------------------------
|
||
| 辅助方法
|
||
|--------------------------------------------------------------------------
|
||
*/
|
||
|
||
/**
|
||
* 检查是否为混装产品
|
||
*/
|
||
private function is_bundle_product($product_id) {
|
||
$bundle = $this->get_product_bundle($product_id);
|
||
return $bundle && $bundle->is_available();
|
||
}
|
||
|
||
/**
|
||
* 获取产品的混装配置
|
||
*/
|
||
private function get_product_bundle($product_id) {
|
||
static $bundles = array();
|
||
|
||
if (!isset($bundles[$product_id])) {
|
||
global $wpdb;
|
||
|
||
$bundle_id = $wpdb->get_var($wpdb->prepare("
|
||
SELECT id FROM {$wpdb->prefix}yoone_bundles
|
||
WHERE product_id = %d AND status = 'active'
|
||
LIMIT 1
|
||
", $product_id));
|
||
|
||
if ($bundle_id) {
|
||
$bundles[$product_id] = new Yoone_Bundle($bundle_id);
|
||
} else {
|
||
$bundles[$product_id] = false;
|
||
}
|
||
}
|
||
|
||
return $bundles[$product_id];
|
||
}
|
||
|
||
/**
|
||
* 格式化混装商品显示
|
||
*/
|
||
private function format_bundle_items($bundle_items) {
|
||
$formatted = array();
|
||
|
||
foreach ($bundle_items as $product_id => $quantity) {
|
||
$product = wc_get_product($product_id);
|
||
if ($product) {
|
||
$formatted[] = sprintf('%s × %d', $product->get_name(), $quantity);
|
||
}
|
||
}
|
||
|
||
return implode(', ', $formatted);
|
||
}
|
||
|
||
/**
|
||
* 格式化选择的商品为计算格式
|
||
*/
|
||
private function format_selected_items($selected_items) {
|
||
$formatted = array();
|
||
|
||
foreach ($selected_items as $product_id => $quantity) {
|
||
$formatted[] = array(
|
||
'product_id' => $product_id,
|
||
'quantity' => $quantity,
|
||
'discount_type' => 'none',
|
||
'discount_value' => 0,
|
||
'is_required' => false,
|
||
'sort_order' => 0
|
||
);
|
||
}
|
||
|
||
return $formatted;
|
||
}
|
||
}
|
||
|
||
// 初始化
|
||
new Yoone_Bundle_Frontend(); |