yoone-wc-product-bundles/includes/frontend/class-yoone-product-bundles...

133 lines
5.3 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
/**
* 前端:渲染混装产品的自定义 add-to-cart 表单、校验并加入购物车。
*/
defined('ABSPATH') || exit;
class Yoone_Product_Bundles_Frontend {
protected static $instance = null;
public static function instance() {
if (null === self::$instance) self::$instance = new self();
return self::$instance;
}
private function __construct() {
// 用我们的模板替换默认的 add-to-cart 按钮
add_action('woocommerce_' . Yoone_Product_Bundles::TYPE . '_add_to_cart', array($this, 'render_add_to_cart')); // 显示表单
// 处理加入购物车:校验数量并打包所选组件数据
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);
}
/**
* 渲染自定义表单:按所选分类分组显示允许的简单商品,提供数量输入。
*/
public function render_add_to_cart() {
wc_get_template('single-product/add-to-cart/yoone-bundle.php', array(), '', YOONE_PB_PATH . 'templates/');
}
/**
* 校验:总选择数量 >= min_qty
*/
public function validate_add_to_cart($passed, $product_id, $quantity, $variation_id, $variations, $cart_item_data) {
$product = wc_get_product($product_id);
if (! $product || $product->get_type() !== Yoone_Product_Bundles::TYPE) return $passed;
$config = Yoone_Product_Bundles::get_bundle_config($product);
$min = max(0, absint($config['min_qty']));
// 从 POST 中收集数量
$selected = isset($_POST['yoone_bundle_components']) ? (array) $_POST['yoone_bundle_components'] : array();
$total_qty = 0;
foreach ($selected as $pid => $qty) {
$qty = absint($qty);
if ($qty > 0) $total_qty += $qty;
}
if ($total_qty < $min) {
wc_add_notice(sprintf(__('请至少选择 %d 件混装组件后再加入购物车。', 'yoone-product-bundles'), $min), '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 || $product->get_type() !== Yoone_Product_Bundles::TYPE) return $cart_item_data;
$selected = isset($_POST['yoone_bundle_components']) ? (array) $_POST['yoone_bundle_components'] : array();
// 仅保留大于 0 的数量
$components = array();
foreach ($selected as $pid => $qty) {
$pid = absint($pid);
$qty = absint($qty);
if ($pid && $qty > 0) $components[$pid] = $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'])) {
$lines = array();
foreach ($cart_item['yoone_bundle_components'] as $pid => $qty) {
$p = wc_get_product($pid);
if ($p) {
$lines[] = sprintf('%s × %d', $p->get_name(), $qty);
}
}
if (! empty($lines)) {
$item_data[] = array(
'key' => __('混装内容', 'yoone-product-bundles'),
'value' => implode("\n", $lines),
'display' => implode('<br/>', array_map('esc_html', $lines)),
);
}
}
return $item_data;
}
/**
* 结算前根据组件动态调整混装产品的行项目价格(= 所选简单商品单价 × 数量 的总和)。
* 注意:这里使用的是产品当前价格(不含税的基础价),是否包含税由 WooCommerce 税设置决定。
*/
public function adjust_bundle_price($cart) {
if (is_admin() && ! defined('DOING_AJAX')) {
return; // 后台不处理
}
if (empty($cart) || ! method_exists($cart, 'get_cart')) return;
foreach ($cart->get_cart() as $cart_item_key => $cart_item) {
if (empty($cart_item['yoone_bundle_components'])) continue;
$product = isset($cart_item['data']) ? $cart_item['data'] : null;
if (! $product || ! is_a($product, 'WC_Product')) continue;
if ($product->get_type() !== Yoone_Product_Bundles::TYPE) continue;
$total = 0.0;
foreach ($cart_item['yoone_bundle_components'] as $pid => $qty) {
$p = wc_get_product($pid);
if (! $p) continue;
$unit = floatval($p->get_price()); // 基础价
$total += $unit * absint($qty);
}
// 将产品行项目价格设为总价
$product->set_price($total);
}
}
}