skip to Main Content

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?

2

Answers


  1. 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.

    Login or Signup to reply.
  2. 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;
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search