phpwordpresswoocommercehook-woocommerce

Remove WooCommerce default variation dropdowns and allow product options to be send


I created a product variation table where clients select a color then the size table gets displayed, the table has a size quantity box and adds to the cart, and it all works but for some reason, I cannot get the original dropdowns to be removed I have tried a few ways but for some reason, none of them is working.

Here are the remove variations I tried:

// Remove default variation dropdowns
add_action('wp_enqueue_scripts', 'remove_variation_dropdowns', 20);
function remove_variation_dropdowns() { 
    wp_dequeue_script('wc-add-to-cart-variation'); 
}

Then this:

// Remove the default WooCommerce variation form
remove_action('woocommerce_single_variation', 'woocommerce_single_variation_add_to_cart_button', 20);
remove_action('woocommerce_before_single_variation', 'woocommerce_single_variation', 10);
remove_action('woocommerce_before_add_to_cart_form', 'woocommerce_variable_add_to_cart', 30); 

But the product options field that does not get send when variations are being added to the cart.

See the screenshot (red is what I want removed and blue is what needs to be sent when client clicks add to cart on variation table):
red is what i want removed and blue is what needs to be send when client clicks add to cart on variation table

This is my code (in three parts):

1st part:

add_action('woocommerce_single_product_summary', 'custom_variation_table', 20);

function custom_variation_table() {
    global $product;

    if (!$product->is_type('variable')) return; // Only show for variable products

    $attributes = $product->get_attributes(); // Get product attributes
    $variations = $product->get_available_variations();
    
    // Get Colors if Available
    $colors = isset($attributes['pa_color']) ? wc_get_product_terms($product->get_id(), 'pa_color', ['fields' => 'names']) : [];

    // Display Color Swatches
    if (!empty($colors)) {
        echo '<div id="color-filter" class="color-swatch-container" aria-label="Color Options">';
        foreach ($colors as $color) {
            $color_slug = strtolower(sanitize_title($color)); // Generate slug
            $is_available = check_color_availability($color_slug, $variations);

            $class = $is_available ? 'color-swatch' : 'color-swatch disabled';
            echo '<button 
                    class="' . esc_attr($class) . '" 
                    data-color="' . esc_attr($color_slug) . '" 
                    aria-label="' . esc_attr($color) . '"
                    title="' . esc_attr($color) . '" 
                    style="background-color:' . esc_attr($color_slug) . ';"
                    ' . ($is_available ? '' : 'disabled aria-disabled="true"') . '>
                  </button>';
        }
        echo '</div>';
    }

    // Display Variation Table
    echo '<div class="variation-table-wrapper">
            <table class="variation-table">
                <thead>
                    <tr>
                        <th>Size</th>
                        <th>Price</th>
                        <th>Quantity</th>
                        <th>Add to Cart</th>
                    </tr>
                </thead>
                <tbody>';

    foreach ($variations as $variation) {
        $variation_obj = new WC_Product_Variation($variation['variation_id']);
        $variation_price = $variation_obj->get_price_html();
        $attributes = $variation_obj->get_attributes();

        $color = strtolower($attributes['pa_color'] ?? '');
        $size = $attributes['pa_size'] ?? 'N/A';

        echo '<tr class="variation-row" data-color="' . esc_attr($color) . '">
                <td>' . esc_html(strtoupper($size)) . '</td>
                <td>' . $variation_price . '</td>
                <td><input type="number" name="quantity[' . esc_attr($variation['variation_id']) . ']" value="1" min="1" style="width: 4em;"></td>
                <td><button class="add-to-cart-btn" data-product-id="' . esc_attr($product->get_id()) . '" data-variation-id="' . esc_attr($variation['variation_id']) . '">Add to Cart</button></td>
              </tr>';
    }

    echo '</tbody></table></div>';

    // Add Scripts and Styles
    enqueue_custom_scripts();
}

function check_color_availability($color_slug, $variations) {
    foreach ($variations as $variation) {
        $attributes = $variation['attributes'];
        if (isset($attributes['attribute_pa_color']) && $attributes['attribute_pa_color'] === $color_slug) {
            return true;
        }
    }
    return false;
}

function enqueue_custom_scripts() {
    ?>
    <script type="text/javascript">
        jQuery(document).ready(function ($) {
            // Handle swatch click
            $('.color-swatch:not(.disabled)').on('click', function () {
                var selectedColor = $(this).data('color');
                $('.color-swatch').removeClass('selected');
                $(this).addClass('selected');

                $('.variation-row').each(function () {
                    $(this).toggle($(this).data('color') === selectedColor);
                });

                $('.variation-table').fadeIn();
            });

            // Add to Cart
           $('.add-to-cart-btn').on('click', function () {
    var button = $(this);
    var productId = button.data('product-id');
    var variationId = button.data('variation-id');
    var quantity = button.closest('tr').find('input[type="number"]').val();

    $.ajax({
        url: '<?php echo admin_url('admin-ajax.php'); ?>',
        type: 'POST',
        data: {
            action: 'add_variation_to_cart',
            product_id: productId,
            variation_id: variationId,
            quantity: quantity
        },
        beforeSend: function () {
            button.text('Adding...');
        },
        success: function (response) {
            if (response.success) {
                alert(response.data.message);
                $(document.body).trigger('wc_fragment_refresh');
            } else {
                alert(response.data.message);
            }
            button.text('Add to Cart');
        },
        error: function () {
            alert('Error adding to cart.');
            button.text('Add to Cart');
        }
    });
});
            });
    </script>
    <style>
        /* Styles remain unchanged from the original */
        .variation-table { display: none; }
        .color-swatch-container { display: flex; gap: 10px; margin-bottom: 20px; }

.color-swatch {
    width: 40px; /* Width of the swatch */
    height: 40px; /* Height of the swatch */
    padding:0 !important;
    border-radius: 50px; /* Makes the swatch round */
    border: 2px solid #ccc; /* Add a border for better visibility */
    cursor: pointer; /* Pointer cursor on hover */
    transition: transform 0.2s, border-color 0.2s; /* Smooth hover effects */
}

.color-swatch:hover {
    transform: scale(1.1); /* Slightly enlarge on hover */
    border-color: #333; /* Change border color on hover */
}

.color-swatch[data-color="white"] {
    border: 2px solid #000; /* Add a black border for white swatches */
}
        .color-swatch.selected {
    border-color: #000; /* Dark border for the selected swatch */
    box-shadow: 0 0 5px rgba(0, 0, 0, 0.5); /* Add a subtle shadow */
}
        .color-swatch.disabled {
    opacity: 0.5; /* Make the swatch appear greyed out */
    cursor: not-allowed; /* Change cursor to indicate unavailability */
    transform: none; /* Remove hover effects */
    border-color: #aaa; /* Light border for disabled swatches */
}
.variation .qty {
    width: 3.631em;
    text-align: center;
    min-height: 35px;
}
    </style>
    <?php
}

2nd part:

add_action('wp_ajax_add_variation_to_cart', 'custom_add_variation_to_cart');
add_action('wp_ajax_nopriv_add_variation_to_cart', 'custom_add_variation_to_cart');

function custom_add_variation_to_cart() {
    $product_id = intval($_POST['product_id']);
    $variation_id = intval($_POST['variation_id']);
    $quantity = intval($_POST['quantity']);

    if ($product_id && $variation_id && $quantity > 0) {
        $added = WC()->cart->add_to_cart($product_id, $quantity, $variation_id);

        if ($added) {
            wp_send_json_success(['message' => 'Item added to cart successfully!']);
        } else {
            wp_send_json_error(['message' => 'Failed to add item to cart.']);
        }
    } else {
        wp_send_json_error(['message' => 'Invalid data provided.']);
    }

    wp_die();
}

3rd part:

function enqueue_woocommerce_scripts() {
    wp_enqueue_script('jquery');
    wp_enqueue_script('wc-add-to-cart', plugins_url('woocommerce/assets/js/frontend/add-to-cart.min.js'), ['jquery'], WC_VERSION, true);
}
add_action('wp_enqueue_scripts', 'enqueue_woocommerce_scripts');

Solution

  • There is a much simpler way to make it work, removing the variable add to cart template like:

    // Replace variable products form
    add_action('woocommerce_single_product_summary', 'customize_variable_product_form', 1);
    function customize_variable_product_form() {
        global $product;
    
        if ( $product->is_type('variable') ) {
            remove_action('woocommerce_single_product_summary', 'woocommerce_template_single_add_to_cart', 30);
            add_action('woocommerce_single_product_summary', 'display_custom_variation_table', 30);
        }
    }
    
    function display_custom_variation_table() {
        global $product;
    
        $attributes = $product->get_attributes(); // Get product attributes
        $variations = $product->get_available_variations();
        
        // Get Colors if Available
        $colors = isset($attributes['pa_color']) ? wc_get_product_terms($product->get_id(), 'pa_color', ['fields' => 'names']) : [];
    
        do_action( 'woocommerce_before_add_to_cart_form' );
    
        // Display Color Swatches
        if ( !empty($colors) ) {
            echo '<div id="color-filter" class="color-swatch-container" aria-label="Color Options">';
            foreach ($colors as $color) {
                $color_slug = strtolower(sanitize_title($color)); // Generate slug
                $is_available = check_color_availability($color_slug, $variations);
    
                $class = $is_available ? 'color-swatch' : 'color-swatch disabled';
                echo '<button 
                        class="' . esc_attr($class) . '" 
                        data-color="' . esc_attr($color_slug) . '" 
                        aria-label="' . esc_attr($color) . '"
                        title="' . esc_attr($color) . '" 
                        style="background-color:' . esc_attr($color_slug) . ';"
                        ' . ($is_available ? '' : 'disabled aria-disabled="true"') . '>
                      </button>';
            }
            echo '</div>';
        }
    
        // Display Variation Table
        echo '<div class="variation-table-wrapper">
                <table class="variation-table">
                    <thead>
                        <tr>
                            <th>Size</th>
                            <th>Price</th>
                            <th>Quantity</th>
                            <th>Add to Cart</th>
                        </tr>
                    </thead>
                    <tbody>';
    
        foreach ($variations as $variation) {
            $variation_obj = new WC_Product_Variation($variation['variation_id']);
            $variation_price = $variation_obj->get_price_html();
            $attributes = $variation_obj->get_attributes();
    
            $color = strtolower($attributes['pa_color'] ?? '');
            $size = $attributes['pa_size'] ?? 'N/A';
    
            echo '<tr class="variation-row" data-color="' . esc_attr($color) . '">
                    <td>' . esc_html(strtoupper($size)) . '</td>
                    <td>' . $variation_price . '</td>
                    <td><input type="number" name="quantity[' . esc_attr($variation['variation_id']) . ']" value="1" min="1" style="width: 4em;"></td>
                    <td><button class="add-to-cart-btn" data-product-id="' . esc_attr($product->get_id()) . '" data-variation-id="' . esc_attr($variation['variation_id']) . '">Add to Cart</button></td>
                  </tr>';
        }
    
        echo '</tbody></table></div>';
    
        // Add Scripts and Styles
        enqueue_custom_scripts();
    
        do_action( 'woocommerce_after_variations_form' );
    }
    
    function check_color_availability($color_slug, $variations) {
        foreach ($variations as $variation) {
            $attributes = $variation['attributes'];
            if (isset($attributes['attribute_pa_color']) && $attributes['attribute_pa_color'] === $color_slug) {
                return true;
            }
        }
        return false;
    }
    
    function enqueue_custom_scripts() {
        ?>
        <script type="text/javascript">
            jQuery(document).ready(function ($) {
                // Handle swatch click
                $('.color-swatch:not(.disabled)').on('click', function () {
                    var selectedColor = $(this).data('color');
                    $('.color-swatch').removeClass('selected');
                    $(this).addClass('selected');
    
                    $('.variation-row').each(function () {
                        $(this).toggle($(this).data('color') === selectedColor);
                    });
    
                    $('.variation-table').fadeIn();
                });
    
                // Add to Cart
               $('.add-to-cart-btn').on('click', function () {
        var button = $(this);
        var productId = button.data('product-id');
        var variationId = button.data('variation-id');
        var quantity = button.closest('tr').find('input[type="number"]').val();
    
        $.ajax({
            url: '<?php echo admin_url('admin-ajax.php'); ?>',
            type: 'POST',
            data: {
                action: 'add_variation_to_cart',
                product_id: productId,
                variation_id: variationId,
                quantity: quantity
            },
            beforeSend: function () {
                button.text('Adding...');
            },
            success: function (response) {
                if (response.success) {
                    alert(response.data.message);
                    $(document.body).trigger('wc_fragment_refresh');
                } else {
                    alert(response.data.message);
                }
                button.text('Add to Cart');
            },
            error: function () {
                alert('Error adding to cart.');
                button.text('Add to Cart');
            }
        });
    });
                });
        </script>
        <style>
            /* Styles remain unchanged from the original */
            .variation-table { display: none; }
            .color-swatch-container { display: flex; gap: 10px; margin-bottom: 20px; }
    
    .color-swatch {
        width: 40px; /* Width of the swatch */
        height: 40px; /* Height of the swatch */
        padding:0 !important;
        border-radius: 50px; /* Makes the swatch round */
        border: 2px solid #ccc; /* Add a border for better visibility */
        cursor: pointer; /* Pointer cursor on hover */
        transition: transform 0.2s, border-color 0.2s; /* Smooth hover effects */
    }
    
    .color-swatch:hover {
        transform: scale(1.1); /* Slightly enlarge on hover */
        border-color: #333; /* Change border color on hover */
    }
    
    .color-swatch[data-color="white"] {
        border: 2px solid #000; /* Add a black border for white swatches */
    }
            .color-swatch.selected {
        border-color: #000; /* Dark border for the selected swatch */
        box-shadow: 0 0 5px rgba(0, 0, 0, 0.5); /* Add a subtle shadow */
    }
            .color-swatch.disabled {
        opacity: 0.5; /* Make the swatch appear greyed out */
        cursor: not-allowed; /* Change cursor to indicate unavailability */
        transform: none; /* Remove hover effects */
        border-color: #aaa; /* Light border for disabled swatches */
    }
    .variation .qty {
        width: 3.631em;
        text-align: center;
        min-height: 35px;
    }
        </style>
        <?php
    }
    
    add_action('wp_ajax_add_variation_to_cart', 'custom_add_variation_to_cart');
    add_action('wp_ajax_nopriv_add_variation_to_cart', 'custom_add_variation_to_cart');
    
    function custom_add_variation_to_cart() {
        $product_id = intval($_POST['product_id']);
        $variation_id = intval($_POST['variation_id']);
        $quantity = intval($_POST['quantity']);
    
        if ($product_id && $variation_id && $quantity > 0) {
            $added = WC()->cart->add_to_cart($product_id, $quantity, $variation_id);
    
            if ($added) {
                wp_send_json_success(['message' => 'Item added to cart successfully!']);
            } else {
                wp_send_json_error(['message' => 'Failed to add item to cart.']);
            }
        } else {
            wp_send_json_error(['message' => 'Invalid data provided.']);
        }
    
        wp_die();
    }
    
    function enqueue_woocommerce_scripts() {
        wp_dequeue_script('wc-add-to-cart-variation'); 
        wp_enqueue_script('jquery');
        wp_enqueue_script('wc-add-to-cart', plugins_url('woocommerce/assets/js/frontend/add-to-cart.min.js'), ['jquery'], WC_VERSION, true);
    }
    add_action('wp_enqueue_scripts', 'enqueue_woocommerce_scripts');
    

    Code goes in functions.php file of your child theme (or in a plugin).