setup_hooks(); } /** * 设置所有与前端相关的钩子。 */ public function setup_hooks() { // Handle the custom add-to-cart process for bundles add_filter('woocommerce_add_to_cart_validation', array($this, 'process_bundle_add_to_cart'), 10, 3); // When a bundle container is removed, remove its children. add_action('woocommerce_cart_item_removed', array($this, 'remove_bundle_children'), 10, 2); // Hide the "remove" link for child items in the cart. add_filter('woocommerce_cart_item_remove_link', array($this, 'hide_child_remove_link'), 10, 2); // In the cart, show which bundle a child item belongs to. add_filter('woocommerce_get_item_data', array($this, 'display_child_bundle_link'), 10, 2); // Add a body class to the bundle product page for easier styling. add_filter('body_class', array($this, 'filter_body_class')); // Replace the default "Add to Cart" button with our custom form. 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; } }