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):
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');
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).