176 lines
6.1 KiB
PHP
176 lines
6.1 KiB
PHP
<?php
|
||
/**
|
||
* 前端:渲染混装产品的自定义 add-to-cart 表单、校验并加入购物车。
|
||
*/
|
||
defined('ABSPATH') || exit;
|
||
|
||
class Yoone_Product_Bundles_Frontend {
|
||
|
||
private static $_instance = null;
|
||
|
||
public static function instance() {
|
||
if (is_null(self::$_instance)) {
|
||
self::$_instance = new self();
|
||
}
|
||
return self::$_instance;
|
||
}
|
||
|
||
private function __construct() {
|
||
// 加载自定义的混装产品页面模板
|
||
add_filter('template_include', array($this, 'use_bundle_template'), 99);
|
||
|
||
// 处理加入购物车:校验数量并打包所选组件数据
|
||
add_filter('woocommerce_add_to_cart_validation', array($this, 'validate_add_to_cart'), 10, 6);
|
||
add_filter('woocommerce_add_cart_item_data', array($this, 'add_cart_item_data'), 10, 3);
|
||
|
||
// 在购物车/订单中显示组件摘要
|
||
add_filter('woocommerce_get_item_data', array($this, 'display_cart_item_data'), 10, 2);
|
||
|
||
// 结算前动态调整价格
|
||
add_action('woocommerce_before_calculate_totals', array($this, 'adjust_bundle_price'), 20, 1);
|
||
|
||
// 为混装产品页增加 body class,便于主题兼容样式控制
|
||
add_filter('body_class', array($this, 'filter_body_class'));
|
||
|
||
// 从 woocommerce_single_product_summary 钩子中移除默认的 add-to-cart
|
||
add_action('init', array($this, 'remove_default_add_to_cart'));
|
||
}
|
||
|
||
/**
|
||
* 移除默认的 add-to-cart 按钮,因为我们的模板会自己处理
|
||
*/
|
||
public function remove_default_add_to_cart() {
|
||
remove_action('woocommerce_single_product_summary', 'woocommerce_template_single_add_to_cart', 30);
|
||
}
|
||
|
||
/**
|
||
* 如果是混装产品页面,则加载我们的自定义模板。
|
||
*/
|
||
public function use_bundle_template($template) {
|
||
if (is_singular('product')) {
|
||
global $post;
|
||
$product = wc_get_product($post->ID);
|
||
if ($product && $product->get_type() === Yoone_Product_Bundles::TYPE) {
|
||
// 加载插件内的完整页面模板
|
||
$new_template = YOONE_PB_PATH . 'templates/single-product-yoone-bundle.php';
|
||
if (file_exists($new_template)) {
|
||
return $new_template;
|
||
}
|
||
}
|
||
}
|
||
return $template;
|
||
}
|
||
|
||
/**
|
||
* 在混装产品页增加 body class。
|
||
*/
|
||
public function filter_body_class($classes) {
|
||
global $post;
|
||
if (is_singular('product') && $post) {
|
||
$product = wc_get_product($post->ID);
|
||
if ($product && $product->get_type() === Yoone_Product_Bundles::TYPE) {
|
||
$classes[] = 'yoone-bundle-product';
|
||
}
|
||
}
|
||
return $classes;
|
||
}
|
||
|
||
/**
|
||
* 校验混装产品加入购物车:至少选择一个组件。
|
||
*/
|
||
public function validate_add_to_cart($passed, $product_id, $quantity, $variation_id = null, $variations = null, $cart_item_data = null) {
|
||
$product = wc_get_product($product_id);
|
||
if ($product->get_type() !== Yoone_Product_Bundles::TYPE) {
|
||
return $passed;
|
||
}
|
||
|
||
$config = Yoone_Product_Bundles::get_bundle_config($product);
|
||
$min_qty = max(1, absint($config['min_qty']));
|
||
|
||
$components = !empty($_POST['yoone_bundle_components']) ? $_POST['yoone_bundle_components'] : array();
|
||
$total_qty = 0;
|
||
foreach ($components as $comp_id => $qty) {
|
||
$qty = absint($qty);
|
||
if ($qty > 0) {
|
||
$total_qty += $qty;
|
||
}
|
||
}
|
||
|
||
if ($total_qty < $min_qty) {
|
||
wc_add_notice(sprintf(__('您需要至少选择 %d 件商品才能将此混装包加入购物车。', 'yoone-product-bundles'), $min_qty), 'error');
|
||
return false;
|
||
}
|
||
|
||
return $passed;
|
||
}
|
||
|
||
/**
|
||
* 将混装组件数据添加到购物车项目。
|
||
*/
|
||
public function add_cart_item_data($cart_item_data, $product_id, $variation_id) {
|
||
$product = wc_get_product($product_id);
|
||
if ($product->get_type() !== Yoone_Product_Bundles::TYPE) {
|
||
return $cart_item_data;
|
||
}
|
||
|
||
if (isset($_POST['yoone_bundle_components'])) {
|
||
$components = array();
|
||
foreach ($_POST['yoone_bundle_components'] as $comp_id => $qty) {
|
||
$qty = absint($qty);
|
||
if ($qty > 0) {
|
||
$components[absint($comp_id)] = $qty;
|
||
}
|
||
}
|
||
if (!empty($components)) {
|
||
$cart_item_data['yoone_bundle_components'] = $components;
|
||
}
|
||
}
|
||
|
||
return $cart_item_data;
|
||
}
|
||
|
||
/**
|
||
* 在购物车和订单中显示混装组件的摘要。
|
||
*/
|
||
public function display_cart_item_data($item_data, $cart_item) {
|
||
if (empty($cart_item['yoone_bundle_components'])) {
|
||
return $item_data;
|
||
}
|
||
|
||
$value = "";
|
||
foreach ($cart_item['yoone_bundle_components'] as $pid => $qty) {
|
||
$product = wc_get_product($pid);
|
||
if ($product) {
|
||
$value .= $product->get_name() . ' × ' . $qty . "; ";
|
||
}
|
||
}
|
||
|
||
$item_data[] = array(
|
||
'key' => __('混装明细', 'yoone-product-bundles'),
|
||
'value' => rtrim($value, "; "),
|
||
'display' => ''
|
||
);
|
||
|
||
return $item_data;
|
||
}
|
||
|
||
/**
|
||
* 在将商品添加到购物车之前,根据所选组件动态计算混装产品的总价。
|
||
*/
|
||
public function adjust_bundle_price($cart) {
|
||
if (is_admin() && !defined('DOING_AJAX')) return;
|
||
|
||
foreach ($cart->get_cart() as $cart_item_key => $cart_item) {
|
||
if (isset($cart_item['yoone_bundle_components'])) {
|
||
$total_price = 0;
|
||
foreach ($cart_item['yoone_bundle_components'] as $pid => $qty) {
|
||
$product = wc_get_product($pid);
|
||
if ($product) {
|
||
$total_price += (float) $product->get_price() * $qty;
|
||
}
|
||
}
|
||
$cart_item['data']->set_price($total_price);
|
||
}
|
||
}
|
||
}
|
||
} |