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

184 lines
6.9 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
/**
* 前端:为混装产品渲染自定义的“添加到购物车”表单,并处理验证和加入购物车的逻辑。
*/
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() {
$this->setup_hooks();
}
/**
* 设置所有与前端相关的钩子。
*/
public function setup_hooks() {
// 处理混装产品的自定义“添加到购物车”流程
add_filter('woocommerce_add_to_cart_validation', array($this, 'process_bundle_add_to_cart'), 10, 3);
// 当混装容器被移除时,移除其子项目
add_action('woocommerce_cart_item_removed', array($this, 'remove_bundle_children'), 10, 2);
// 隐藏购物车中子项目的“移除”链接
add_filter('woocommerce_cart_item_remove_link', array($this, 'hide_child_remove_link'), 10, 2);
// 在购物车中,显示子项目所属的混装产品
add_filter('woocommerce_get_item_data', array($this, 'display_child_bundle_link'), 10, 2);
// 为混装产品页面添加 body class以便于样式化
add_filter('body_class', array($this, 'filter_body_class'));
// 用我们的自定义表单替换默认的“添加到购物车”按钮
add_action('woocommerce_single_product_summary', array($this, 'remove_default_add_to_cart_for_bundle'), 29);
add_action('woocommerce_single_product_summary', array($this, 'render_bundle_add_to_cart_form'), 30);
}
/**
* Hijack the add-to-cart process for bundle products.
* Validates the submission, then adds the container and all child products to the cart.
*
* @return bool False to prevent the default add-to-cart action.
*/
public function process_bundle_add_to_cart($passed, $product_id, $quantity) {
$product = wc_get_product($product_id);
if (!$product || $product->get_type() !== Yoone_Product_Bundles::TYPE) {
return $passed; // Not our product, pass through.
}
// 1. Validation
$config = Yoone_Product_Bundles::get_bundle_config($product);
$min_qty = max(1, absint($config['min_qty']));
$components = !empty($_POST['yoone_bundle_components']) ? (array) $_POST['yoone_bundle_components'] : array();
$total_qty = 0;
$clean_components = array();
foreach ($components as $comp_id => $qty) {
$qty = absint($qty);
if ($qty > 0) {
$total_qty += $qty;
$clean_components[absint($comp_id)] = $qty;
}
}
if ($total_qty < $min_qty) {
wc_add_notice(sprintf(__('You need to select at least %d items to add this bundle to your cart.', 'yoone-product-bundles'), $min_qty), 'error');
return false;
}
// 2. Add items to cart
try {
$bundle_container_id = uniqid('bundle_');
// Add the main bundle product (as a 0-price container)
WC()->cart->add_to_cart($product_id, 1, 0, array(), array('yoone_bundle_container_id' => $bundle_container_id));
// Add child components
foreach ($clean_components as $comp_id => $qty) {
WC()->cart->add_to_cart($comp_id, $qty, 0, array(), array(
'yoone_bundle_parent_id' => $bundle_container_id,
'yoone_bundle_parent_product_id' => $product_id
));
}
// Set success message and redirect
wc_add_to_cart_message(array($product_id => 1), true);
add_filter('woocommerce_add_to_cart_redirect', function() { return wc_get_cart_url(); });
} catch (Exception $e) {
wc_add_notice($e->getMessage(), 'error');
return false;
}
// Prevent default add-to-cart for the main product
return false;
}
/**
* When a cart item is removed, check if it's a bundle container.
* If so, find and remove all its child items.
*/
public function remove_bundle_children($removed_cart_item_key, $cart) {
$removed_item = $cart->get_removed_cart_items()[$removed_cart_item_key];
if (isset($removed_item['yoone_bundle_container_id'])) {
$bundle_container_id = $removed_item['yoone_bundle_container_id'];
foreach ($cart->get_cart() as $cart_item_key => $cart_item) {
if (isset($cart_item['yoone_bundle_parent_id']) && $cart_item['yoone_bundle_parent_id'] === $bundle_container_id) {
$cart->remove_cart_item($cart_item_key);
}
}
}
}
/**
* Hide the remove link for child items of a bundle.
*/
public function hide_child_remove_link($link, $cart_item_key) {
$cart_item = WC()->cart->get_cart_item($cart_item_key);
if (isset($cart_item['yoone_bundle_parent_id'])) {
return '';
}
return $link;
}
/**
* For child items, add a meta line in the cart to link back to the parent bundle.
*/
public function display_child_bundle_link($item_data, $cart_item) {
if (isset($cart_item['yoone_bundle_parent_product_id'])) {
$parent_product = wc_get_product($cart_item['yoone_bundle_parent_product_id']);
if ($parent_product) {
$item_data[] = array(
'key' => __('Part of', 'yoone-product-bundles'),
'value' => $parent_product->get_name(),
);
}
}
return $item_data;
}
/**
* Remove the default "Add to Cart" button for bundle products only.
*/
public function remove_default_add_to_cart_for_bundle() {
global $product;
if ($product && $product->get_type() === Yoone_Product_Bundles::TYPE) {
remove_action('woocommerce_single_product_summary', 'woocommerce_template_single_add_to_cart', 30);
}
}
/**
* Render the custom "Add to Cart" form for bundle products.
*/
public function render_bundle_add_to_cart_form() {
global $product;
if ($product && $product->get_type() === Yoone_Product_Bundles::TYPE) {
wc_get_template('global/yoone-bundle-form.php', array(), '', YOONE_PB_PATH . 'templates/');
}
}
/**
* Add a body class for bundle product pages.
*/
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;
}
}