Thêm nút xóa và tăng giảm số lượng sản phẩm trong trang thanh toán WooCommerce đối với các bạn sử dụng wordpress plugin Woocommerce
- Tăng giảm số lượng trực tiếp ở trang thanh toán cho từng sản phẩm
- Xóa từng sản phẩm đã thêm vào giỏ hàng ngay trực tiếp trang thanh toán
Cho code sau vào file funtion.php
function add_flatsome_product_controls_checkout_wat($product_subtotal, $cart_item, $cart_item_key) {
if (!is_checkout()) {
return $product_subtotal;
}
$quantity = $cart_item['quantity'];
$nonce = wp_create_nonce('woocommerce-cart');
// html
$controls_html = sprintf(
'<div class="checkout-product-controls_wat">
<div class="product-total-price-wat">%s</div>
<div class="product-controls-wrapper-wat">
<div class="quantity-controls flatsome-quantity-wat buttons_added">
<input type="button" value="-" class="minuswat button is-form" data-cart-key="%s">
<input type="number" class="quantity-input" value="%s" min="1" step="1" data-cart-key="%s">
<input type="button" value="+" class="pluswat button is-form" data-cart-key="%s">
</div>
<a href="%s" class="remove-product-wat remove" aria-label="%s" data-product_id="%s">×</a>
</div>
</div>',
$product_subtotal,
esc_attr($cart_item_key),
esc_html($quantity),
esc_attr($cart_item_key),
esc_attr($cart_item_key),
esc_url(wc_get_cart_remove_url($cart_item_key)),
esc_html__('Xóa sản phẩm này', 'flatsome'),
esc_attr($cart_item['product_id'])
);
// CSS styles
$style = '
<style>
/* Container cho tất cả controls */
.checkout-product-controls_wat {
display: flex;
flex-direction: column;
gap: 10px;
}
/* Style cho phần giá */
.product-total-price-wat {
margin-bottom: 5px;
}
/* Wrapper cho phần controls */
.product-controls-wrapper-wat {
display: flex;
gap: 10px;
align-items: center;
}
/* Style cho phần quantity controls */
.flatsome-quantity-wat {
display: inline-flex;
align-items: center;
border: 1px solid #ddd;
border-radius: 3px;
overflow-x: hidden;
}
.flatsome-quantity-wat .button.is-form {
border-radius: 0;
background-color: #f9f9f9;
border: none;
height: 25px;
width: 25px;
padding: 0;
margin: 0;
font-size: 14px;
}
/* Style cho input số lượng */
.flatsome-quantity-wat .quantity-input {
padding: 0 8px;
width: 35px;
text-align: center;
border: none;
background: #fff;
height: 20px;
line-height: 25px;
display: inline-block;
-moz-appearance: textfield;
box-shadow: none;
}
.flatsome-quantity-wat .quantity-input::-webkit-outer-spin-button,
.flatsome-quantity-wat .quantity-input::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}
input.minuswat.button.is-form {
width: 20px;
}
input.pluswat.button.is-form {
width: 20px;
}
/* Style cho nút xóa */
.remove-product-wat {
display: flex;
align-items: center;
justify-content: center;
width: 25px;
height: 25px;
color: #ccc !important;
font-size: 20px !important;
font-weight: bold;
text-decoration: none;
border: 1px solid #ddd;
border-radius: 3px;
transition: all 0.2s;
}
.remove-product-wat:hover {
color: #334862 !important;
background-color: #f9f9f9;
}
/* Loading overlay */
.checkout-loading-overlay-wat {
display: none;
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(255, 255, 255, 0.8);
z-index: 9999;
justify-content: center;
align-items: center;
}
.checkout-loading-overlay-wat.active {
display: flex;
}
.checkout-loading-spinner-wat {
width: 50px;
height: 50px;
border: 4px solid #f3f3f3;
border-top: 4px solid #334862;
border-radius: 50%;
animation: spin 1s linear infinite;
}
/* Loading states */
.flatsome-quantity-wat.loading,
.remove-product-wat.loading {
opacity: 0.5;
pointer-events: none;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
/* Responsive */
@media (max-width: 849px) {
.flatsome-quantity-wat .button.is-form,
.remove-product-wat {
height: 30px;
width: 30px;
}
}
</style>
';
// JavaScript
$script = '
<script>
jQuery(document).ready(function($) {
var ajaxUrl = "' . admin_url('admin-ajax.php') . '";
var nonce = "' . $nonce . '";
var isUpdating = false;
var updateTimeout;
// Thêm overlay loading vào body nếu chưa có
if (!$(".checkout-loading-overlay-wat").length) {
$("body").append(\'<div class="checkout-loading-overlay-wat"><div class="checkout-loading-spinner-wat"></div></div>\');
}
function showLoadingwat() {
$(".checkout-loading-overlay-wat").addClass("active");
}
function hideLoadingwat() {
$(".checkout-loading-overlay-wat").removeClass("active");
}
function updateQuantitywat(cartKey, newQuantity, element) {
if (isUpdating) return;
var controls = element.closest(".flatsome-quantity-wat");
var quantityInput = controls.find(".quantity-input");
// Kiểm tra giá trị tối thiểu
if (newQuantity < 1) {
newQuantity = 1;
quantityInput.val(1);
return;
}
isUpdating = true;
showLoadingwat();
controls.addClass("loading");
$.ajax({
url: ajaxUrl,
type: "POST",
data: {
action: "flatsome_update_quantity",
cart_key: cartKey,
quantity: newQuantity,
security: nonce
},
success: function(response) {
if(response.success) {
quantityInput.val(newQuantity);
$("body").trigger("update_checkout");
// Tính toán tổng số lượng mới
var totalQuantity = 0;
$(".quantity-input").each(function() {
totalQuantity += parseInt($(this).val());
});
// Cập nhật số lượng trực tiếp trên icon giỏ hàng
$(".icon-shopping-cart").attr("data-icon-label", totalQuantity);
} else {
alert("Không thể cập nhật số lượng. Vui lòng tải lại trang.");
quantityInput.val(newQuantity - 1);
}
},
error: function() {
alert("Có lỗi xảy ra. Vui lòng thử lại.");
quantityInput.val(newQuantity - 1);
},
complete: function() {
controls.removeClass("loading");
hideLoadingwat();
isUpdating = false;
}
});
}
// Xử lý nhập số lượng trực tiếp
$(document).on("input", ".quantity-input", function() {
var $this = $(this);
var cartKey = $this.data("cart-key");
var newQuantity = parseInt($this.val());
// Clear timeout cũ nếu có
if (updateTimeout) {
clearTimeout(updateTimeout);
}
// Đặt timeout mới
updateTimeout = setTimeout(function() {
if (!isNaN(newQuantity) && newQuantity > 0) {
updateQuantitywat(cartKey, newQuantity, $this);
}
}, 500); // Đợi 500ms sau khi người dùng ngừng nhập
});
// Ngăn chặn nhập các ký tự không phải số
$(document).on("keypress", ".quantity-input", function(e) {
if (e.which != 8 && e.which != 0 && (e.which < 48 || e.which > 57)) {
return false;
}
});
// Xử lý nút giảm
$(document).on("click", ".flatsome-quantity-wat .minuswat", function() {
if (isUpdating) return;
var cartKey = $(this).data("cart-key");
var quantityInput = $(this).siblings(".quantity-input");
var currentQty = parseInt(quantityInput.val());
if (currentQty > 1) {
updateQuantitywat(cartKey, currentQty - 1, $(this));
}
});
// Xử lý nút tăng
$(document).on("click", ".flatsome-quantity-wat .pluswat", function() {
if (isUpdating) return;
var cartKey = $(this).data("cart-key");
var quantityInput = $(this).siblings(".quantity-input");
var currentQty = parseInt(quantityInput.val());
updateQuantitywat(cartKey, currentQty + 1, $(this));
});
// Xử lý nút xóa cải tiến không reload trang
$(document).on("click", ".remove-product-wat", function(e) {
e.preventDefault();
if (isUpdating) return;
var link = $(this).attr("href");
var $this = $(this);
var $productRow = $this.closest("tr");
isUpdating = true;
showLoadingwat();
$this.addClass("loading");
$.ajax({
url: link,
type: "GET",
success: function() {
$productRow.fadeOut(300, function() {
$(this).remove();
$("body").trigger("update_checkout");
// Tính toán tổng số lượng mới sau khi xóa
var totalQuantity = 0;
$(".quantity-input").each(function() {
totalQuantity += parseInt($(this).val());
});
// Cập nhật số lượng trực tiếp trên icon giỏ hàng
$(".icon-shopping-cart").attr("data-icon-label", totalQuantity);
if ($(".checkout-product-controls_wat").length === 0) {
window.location.reload();
}
});
hideLoadingwat();
isUpdating = false;
},
error: function() {
alert("Có lỗi xảy ra. Vui lòng thử lại.");
hideLoadingwat();
$this.removeClass("loading");
isUpdating = false;
},
complete: function() {
$this.removeClass("loading");
}
});
});
// Xử lý blur input để cập nhật khi click ra ngoài
$(document).on("blur", ".quantity-input", function() {
var $this = $(this);
var cartKey = $this.data("cart-key");
var newQuantity = parseInt($this.val());
if (!isNaN(newQuantity) && newQuantity > 0) {
updateQuantitywat(cartKey, newQuantity, $this);
} else {
$this.val(1);
updateQuantitywat(cartKey, 1, $this);
}
});
});
</script>
';
if (!wp_script_is('flatsome-product-controls-wat', 'enqueued')) {
add_action('wp_footer', function() use ($style, $script) {
echo $style . $script;
});
wp_register_script('flatsome-product-controls-wat', null);
}
return $controls_html;
}
// Xử lý Ajax cho cập nhật số lượng
function handle_flatsome_quantity_update_wat() {
check_ajax_referer('woocommerce-cart', 'security');
$cart_key = sanitize_text_field($_POST['cart_key']);
$quantity = intval($_POST['quantity']);
$success = false;
if ($cart_key && $quantity > 0) {
$success = WC()->cart->set_quantity($cart_key, $quantity);
WC()->cart->calculate_totals();
}
wp_send_json(array('success' => $success));
}
// Đăng ký Ajax actions
add_action('wp_ajax_flatsome_update_quantity', 'handle_flatsome_quantity_update_wat');
add_action('wp_ajax_nopriv_flatsome_update_quantity', 'handle_flatsome_quantity_update_wat');
add_filter('woocommerce_cart_item_subtotal', 'add_flatsome_product_controls_checkout_wat', 10, 3);