Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WooCommerce - Ignore unselected variations when adding to cart

Objective: add product to cart despite unselected variations, i.e. remove/disable the mandatory nature of variation fields.

Issue: WooCommerce's absolute requirement for all variations to be selected before adding to cart.

Tried: filtering out/removing/disabling unselected variations before adding to cart using various hooks; woocommerce_before_calculate_totals, woocommerce_add_to_cart, woocommerce_add_cart_item, woocommerce_add_to_cart_validation

I understand that this is how WooCommerce works and the reasons why it works this way - despite this I still require a work-around.

How do I get around WooCommerce's "all variations selected" requirement so that I may still add a product to the cart even if not all variations are selected?

like image 254
UncaughtTypeError Avatar asked Apr 08 '21 09:04

UncaughtTypeError


People also ask

How do I GREY out stock variations in WooCommerce?

Go to WooCommerce > Settings > Better Variations. Check the checkbox next to the option 'Enable Select2'. Input '#ff0000' in the color picker field 'Out of stock text color' for displaying out-of-stock variation options in red color. Scroll down to the bottom and click the 'Save changes' button.

How do I change the default variation in WooCommerce?

To set default attributes manually, first, in the WooCommerce dashboard go to Products and then click on your variable product. Then, select Variable product from the Product data dropdown. After that, under Variations, you have to select the Default Form Values.

How to add multiple product variations to carts in WooCommerce?

This way can be used with both the same product ID and the different ones Another way to add multiple variations to carts in WooCommerce stores is via a third-party platform. This post will guide you on how to use the plugin WooCommerce Product Table to add more than one product to the cart on one page.

Why is my add to cart button hiding in WooCommerce?

If you’re using a WooCommerce theme, it might come with dedicated theme features for your product pages. This might include hiding your Add to Cart button.

How to empty the cart programatically in WooCommerce?

To better illustrate how to empty the cart programatically, let’s add a button to the cart which would allow customers to click on it and clear their cart. Let’s use the woocommerce_proceed_to_checkout action an echo our very own ‘Submit’ button which will clear the cart for the current customer.

How do I add multiple variations to the cart?

Go to Product and click on Edit to edit the product you want. There, you will see the product ID. There are two ways to add multiple variations to the cart: Copy and paste it after ?add-to-cart=. Then, add &quantity=3 if you want to add two same products to the cart at the same time.


2 Answers

You can try

add_filter('woocommerce_dropdown_variation_attribute_options_args', 'setSelectDefaultVariableOption', 10, 1);
function setSelectDefaultVariableOption($args)
{
    $default = $args['product']->get_default_attributes();
    if (count($args['options']) > 0 && empty($default)) {
        $args['selected'] = $args['options'][0];
    }
    return $args;
}
like image 153
Binh Nguyen Avatar answered Oct 20 '22 16:10

Binh Nguyen


1 - You could use "variation" attributes, and "not-variation" attributes. UPDATED AFTER TESTS

For the attribute that will handle your product price:

  • create a variable product

  • create real Woocommerce product attributes (real taxonomy and terms) (it won't work with "created on product page" attributes, as it'll not create real taxonomy and terms)

  • Here I created 3 attributes with some terms enter image description here

  • On your variable product, I choose all of my 3 attributes. But specified to only use Color and Size for variations (so Color and Variations will handle my prices variations), not the attribute "optional" (that will be an optional option) enter image description here

  • Then, generate your variations. You can see here that I only have variations for a combination of Color and Size, nothing about the "Optional" attribute yet

  • Also, select the "default values" for your variation attributes. So on the frontend, the attribute select HTML input will have a pre-selected option (user can add to cart directly) enter image description here

  • Now we have our variation attributes, with preselected values on the frontend

  • But we still miss our "optional" attributes

  • Add the following code to your function.php or related (Inspired, updated/refreshed, and adapted from this) (sorry for formatting, snippet also available as gist)

  • This will handle outputting the select input for the optional attribute, saving it to cart and to order. You can adapt it to make it required or not, with a default value or not, edit HTML and placement with different hooks.

/**
 * 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', 10, 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', 10, 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 );
    }
}

Results: enter image description here

2 - Plugins

You could also check with plugins like Product Add-Ons or Extra Product Options (Product Addons) for WooCommerce. In addition to real Woocommerce product variations with your attribute handling prices, those plugins could allow you to add optional fields on the product level when adding it to the cart. It can be enough if you don't need real product variations for those "optional" attributes, but only "optional fields that will be saved to the order line-item product".

3 - with hooks (tweaks)

Now, if you really need to use hooks to handle this issue, and you already have variations for required and optional attributes. So you generated all product variations for all attributes. But in the end, only 1 attribute has a price impact, so many variations have the same price).

You could first try to handle it with "default" attributes values. So by only changing the "required price impacting" attribute, the user always has an existing product variation from the combination of attributes. So it can be added to the cart.

If for some reason, you cannot preselect the default yourself: still create the default attribute term, and hook before add to cart. There, from the POST variables, you could:

  • find the required attribute value, and so find back in your DB the corresponding product variation
  • programmatically add to cart the variation with the correct "required" attribute, and the default "non required" attribute.

The thing is with the variable products: attributes are nothing for the checkout process. When user select options (attributes) on the frontend, he selects a combination of attribute that have or not a corresponding product variation (created by admin, or with woocommerce helper). Woocommerce needs an existing product variation (combination of attributes), that you can see on the product page, to add something to the cart. Those variations are in DB a custom post_type "product_variation" that can be added to the cart and to a order as line-item. If the combination of attributes doesn't have a matching product variation: there's nothing to add to the cart.

like image 3
Mtxz Avatar answered Oct 20 '22 17:10

Mtxz