WooCommerce - 添加到购物车时忽略未选择的变体

问题描述

目标:尽管未选择变体,但仍将产品添加到购物车,即删除/禁用变体字段的强制性性质。

问题: WooCommerce 绝对要求在添加到购物车之前选择所有变体。

尝试过:在使用各种钩子添加到购物车之前过滤/删除/禁用未选择的变体; woocommerce_before_calculate_totalswoocommerce_add_to_cartwoocommerce_add_cart_itemwoocommerce_add_to_cart_validation

我知道这就是 WooCommerce 的运作方式以及它以这种方式运作的原因 - 尽管如此,我仍然需要一个变通办法。

如何绕过 WooCommerce 的“选择所有变体”要求,以便即使未选择所有变体,我仍然可以将产品添加到购物车?

解决方法

1 - 您可以使用“variation”属性“not-variation”属性测试后更新

对于将处理您的产品价格的属性:

  • 创建可变产品

  • 创建真实的 Woocommerce 产品属性(真实的分类法和术语)(它不适用于“在产品页面上创建”属性,因为它不会创建真实的分类法和术语)

  • 这里我用一些术语创建了 3 个属性 enter image description here

  • 在您的可变产品上,我选择了所有 3 个属性。但指定仅使用颜色和大小进行变体(因此颜色和变体将处理我的价格变化),而不是属性“可选”(这将是一个可选选项) enter image description here

  • 然后,生成您的变体。你可以在这里看到,我只有颜色和尺寸组合的变体,还没有关于“可选”属性

  • 另外,为您的变体属性选择“默认值”。所以在前端,属性选择 HTML 输入会有一个预先选择的选项(用户可以直接添加到购物车) enter image description here

  • 现在我们有了变体属性,在前端有预选的值

  • 但我们仍然想念我们的“可选”属性

  • 将以下代码添加到您的 function.php 或相关代码(受启发、更新/刷新并改编自 this)(抱歉格式化,代码段也可用作 gist

  • 这将处理输出可选属性的选择输入,将其保存到购物车和订单。您可以调整它以使其成为必需或不需要,是否使用默认值,使用不同的钩子编辑 HTML 和位置。

/**
 * List available attributes on the product page in a drop-down selection
 */
function list_attributes_on_product_page() {
    global $product;
    $attributes = $product->get_attributes();

    if ( ! $attributes ) {
        return;
    }

    //from original script,but here we want to use it for variable products
    /*if ($product->is_type( 'variable' )) {
        return;
    }*/

    echo '<div style="padding-bottom:15px;">';

    foreach ( $attributes as $attribute ) {

        //If product is variable,and attribute is used for variation: woocommerce already handle this input - so it can also be used with attributes of simple products (not variables)
    if($product->is_type( 'variable' ) && $attribute['variation']) {
        continue;
    }

        //get taxonomy for the attribute - eg: Size
        $taxonomy = get_taxonomy($attribute['name']);

        //get terms - eg: small
        $options = wc_get_product_terms( $product->get_id(),$attribute['name'],array( 'fields' => 'all' ) );
        $label = str_replace('Product ','',$taxonomy->label);
        //display select input
        ?>
        <div style="padding-bottom:8px;">
            <label for="attribute[<?php echo $attribute['id']; ?>]"><?php echo $label; ?></label>
            <br />
            <!-- add required attribute or not,handle default with "selected" attribute depending your needs -->
            <select name="attribute[<?php echo $attribute['id']; ?>]" id="attribute[<?php echo $attribute['id']; ?>]">
                <option value disabled selected>Choose an option</option>
                <?php foreach ( $options as $pa ): ?>
                    <option value="<?php echo $pa->name; ?>"><?php echo $pa->name; ?></option>
                <?php endforeach; ?>
            </select>
        </div>
        <?php
    }

    echo '</div>';
}
add_action('woocommerce_before_add_to_cart_button','list_attributes_on_product_page');

/**
 * Add selected attributes to cart items
 */
add_filter('woocommerce_add_cart_item_data','add_attributes_to_cart_item',10,3 );
function add_attributes_to_cart_item( $cart_item_data,$product_id,$variation_id ) {
    $attributes = $_POST['attribute'] ?? null;

    if (empty( $attributes ) ) {
        return $cart_item_data;
    }

    $cart_item_data['attributes'] = serialize($attributes);

    return $cart_item_data;
}

/**
 * Display attributes in cart
 */
add_filter( 'woocommerce_get_item_data','display_attributes_in_cart',2 );
function display_attributes_in_cart( $item_data,$cart_item ) {
    if ( empty( $cart_item['attributes'] ) ) {
        return $item_data;
    }

    foreach (unserialize($cart_item['attributes']) as $attributeID => $value) {
        $attribute = wc_get_attribute($attributeID);
        $item_data[] = array(
            'key'     => $attribute->name,'value'   => $value,'display' => '',);
    }

    return $item_data;
}

/**
 * Add attribute data to order items
 */
add_action( 'woocommerce_checkout_create_order_line_item','add_attributes_to_order_items',4 );
function add_attributes_to_order_items( $item,$cart_item_key,$values,$order ) {
    if ( empty( $values['attributes'] ) ) {
        return;
    }

    foreach (unserialize($values['attributes']) as $attributeID => $value) {
        $attribute = wc_get_attribute($attributeID);
        $item->add_meta_data( $attribute->name,$value );
    }
}

结果: enter image description here

2 - 插件

您还可以使用 Product Add-OnsExtra Product Options (Product Addons) for WooCommerce 等插件进行检查。 除了具有您的属性处理价格的真实 Woocommerce 产品变体之外,这些插件还允许您在将产品添加到购物车时在产品级别添加可选字段。如果您不需要这些“可选”属性的实际产品变体,而只需要“将保存到订单行项目产品中的可选字段”,这就足够了。

3 - 带钩子(调整)

现在,如果您真的需要使用钩子来处理这个问题,并且您已经有了必需和可选属性的变体。因此,您为所有属性生成了所有产品变体。但最终,只有 1 个属性对价格有影响,因此许多变体的价格相同)。

您可以先尝试使用“默认”属性值来处理它。因此,通过仅更改“所需价格影响”属性,用户始终拥有来自属性组合的现有产品变体。因此可以将其添加到购物车中。

如果由于某种原因,您无法自己预先选择默认值:仍然创建默认属性术语,并在添加到购物车之前挂钩。在那里,从 POST 变量中,您可以:

  • 找到所需的属性值,然后在您的数据库中找到相应的产品变体
  • 以编程方式将具有正确“必需”属性和默认“非必需”属性的变体添加到购物车。

问题在于可变产品:结帐过程中没有任何属性。当用户在前端选择选项(属性)时,他选择具有或不具有相应产品变体(由管理员或使用 woocommerce 助手创建)的属性组合。 Woocommerce 需要一个现有的产品变体(属性组合),您可以在产品页面上看到,以向购物车添加一些东西。这些变体在 DB 中是一个自定义的 post_type“product_variation”,可以作为订单项添加到购物车和订单中。 如果属性组合没有匹配的产品变体:没有任何东西可以添加到购物车。

,

你可以试试

add_filter('woocommerce_dropdown_variation_attribute_options_args','setSelectDefaultVariableOption',1);
function setSelectDefaultVariableOption($args)
{
    $default = $args['product']->get_default_attributes();
    if (count($args['options']) > 0 && empty($default)) {
        $args['selected'] = $args['options'][0];
    }
    return $args;
}