WooCommerce 添加到购物车,从自定义 select 字段添加第二个产品

WooCommerce Add to cart, add second product from a custom select field

我需要的

我想简单地实现产品附加组件,而不使用对我的需求来说过于强大的重量级插件。此外,我希望能够跟踪任何插件不提供的附加组件库存。为了让事情更清楚一点,我可以说主要产品是一个吊坠,附加产品是一条链子。客户应该能够 select 吊坠页面上的链条,当他或她单击“添加到购物车”按钮时,两个项目都应添加到购物车。

所以我想我可以把隐藏的单品作为附加品。我的想法是在我的附加产品中添加一个下拉列表,并通过 POST 获得 selected 值,并将其与主要产品一起添加到购物车。到目前为止一切顺利。

我做了什么

这是我的代码:

add_action( 'woocommerce_before_add_to_cart_button', 'chain_selection_field' );
function chain_selection_field() {
    global $product;
    $domain = 'woocommerce';
    $args = array(
    'sku' => 'SOME_TEXT',
    'stock_status' => 'instock',
    );
    $products = wc_get_products( $args );
    foreach ($products as $product) {
        $product_id = $product->get_id();
        $options[$product_id] = $product->get_name();
    }
    woocommerce_form_field('chain_type', array(
        'type'          => 'select',
        'label'         => __('Chain type selection', $domain),
        'required'      => true,
        'options'       => $options,
    ),'');
}

add_action('woocommerce_add_to_cart', 'product_option_add_to_cart');
function product_option_add_to_cart() {
    $product_id = $_POST['chain_type'];
    $found = false;
    if ( sizeof( WC()->cart->get_cart() ) > 0 ) {
        foreach ( WC()->cart->get_cart() as $cart_item_key => $values ) {
            $_product = $values['data'];
            if ( $_product->id == $product_id )
                $found = true;
        }
        if ( ! $found )
            WC()->cart->add_to_cart( $product_id );
    } else {
        WC()->cart->add_to_cart( $product_id );
    }
}

添加到购物车的实现取自此处 - How to add filter or hook for "woocommerce_add_to_cart"

有什么问题?

其实有很多问题:

  1. 只要我 select 下拉列表中的某个值就会永久保留。即使在刷新页面后,即使我选择了另一个值,它仍然会添加到购物车中。看来我必须以某种方式清除 POST 值。我尝试在添加到购物车功能的末尾添加 $_POST = array();unset($_POST);,但这没有用。
  2. 主要产品未添加到购物车 - 当我点击 "add to cart" 时,只有附加产品添加到购物车。我用预设的产品 ID 分别检查了添加到购物车功能,发现它按预期工作并且两个产品都添加到购物车。

问题是我在 foreach 循环中使用了全局变量 $product。所以它打破了循环逻辑并使用全局 $product 而不是所需的数组值。因此,要使代码正常工作,只需将 foreach 循环代码更改为类似以下内容:

foreach ($products as $single_product) {
        $product_id = $single_product->get_id();
        $options[$product_id] = $single_product->get_name();

除此之外,代码运行良好,但我必须做几点说明:

  • 代码只有在通过按添加到购物车按钮提交的 <form> ... </form> 内部调用的钩子插入时才有效,即 woocommerce_before_add_to_cart_buttonwoocommerce_before_add_to_cart_quantitywoocommerce_after_add_to_cart_quantity(你可以在模板中自己检查 - https://github.com/woocommerce/woocommerce/blob/4.1.0/templates/single-product/add-to-cart/simple.php) for simple product and also a few hooks called inside variation loop vor variable product which can be found here - https://github.com/woocommerce/woocommerce/blob/4.1.0/templates/single-product/add-to-cart/variable.php
  • 当通过 woocommerce_before_add_to_cart_button 插入时,输入字段位于产品库存文本和添加到购物车按钮之间,这不是最佳位置,看起来您要么必须编辑模板文件,要么使用 JS 来实现更好的放置使用当前的 WC (4.1) 挂钩。
  • wc_get_products () 函数比较慢。在我的测试中,它比通过 $wpdb->get_results 进行的类似查询慢 10 倍
    • 最好将 product_option_add_to_cart() 自定义函数代码插入 if (isset($_POST['chain_type'])) { ... } 以防止 PHP 在由于某种原因没有 $_POST 值时出现通知