Сделаем чекбоксы и кнопки плюс/минус, а также свою анимацию на странице корзины woocommerce. НЕ ПОДХОДИТ для блочной темы. Корзину можно сделать шорткодом или виджетом корзина от Elementor.

Добавляем сниппет код
/* -----------------------------
Qty plus/minus buttons (cart)
------------------------------ */
add_action( 'woocommerce_after_quantity_input_field', function () {
if ( is_cart() ) {
echo '<button type="button" class="plus">+</button>';
}
}, 25 );
add_action( 'woocommerce_before_quantity_input_field', function () {
if ( is_cart() ) {
echo '<button type="button" class="minus">−</button>';
}
}, 25 );
/* ---------------------------------------------
Enqueue JS + pass ajaxurl + nonce (cart only)
---------------------------------------------- */
add_action( 'wp_enqueue_scripts', function () {
if ( ! is_cart() ) {
return;
}
wp_enqueue_script(
'cart-checkbox-selection',
get_stylesheet_directory_uri() . '/js/cart-checkbox-selection.js',
[ 'jquery' ],
null,
true
);
wp_localize_script( 'cart-checkbox-selection', 'my_cart_select', [
'ajaxurl' => admin_url( 'admin-ajax.php' ),
'nonce' => wp_create_nonce( 'avs_cart_select_nonce' ),
] );
} );
/* ---------------------------------------
AJAX: remove unchecked cart items
---------------------------------------- */
add_action( 'wp_ajax_remove_unchecked_cart_items', 'avs_remove_unchecked_cart_items' );
add_action( 'wp_ajax_nopriv_remove_unchecked_cart_items', 'avs_remove_unchecked_cart_items' );
function avs_remove_unchecked_cart_items() {
// 1) Validate payload
if ( empty( $_POST['checked'] ) || ! is_array( $_POST['checked'] ) ) {
wp_send_json_error( [ 'message' => 'No items received' ], 400 );
}
// 2) Nonce
$nonce = isset( $_POST['nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : '';
if ( ! $nonce || ! wp_verify_nonce( $nonce, 'avs_cart_select_nonce' ) ) {
wp_send_json_error( [ 'message' => 'Bad nonce' ], 403 );
}
// 3) Cart exists
if ( ! function_exists( 'WC' ) || ! WC()->cart ) {
wp_send_json_error( [ 'message' => 'Cart not available' ], 500 );
}
$checked_items = array_map(
static function ( $v ) {
return sanitize_text_field( wp_unslash( $v ) );
},
$_POST['checked']
);
$checked_map = array_flip( $checked_items );
// 4) Decide what to remove
$current_cart = WC()->cart->get_cart();
$to_remove = [];
foreach ( $current_cart as $cart_key => $cart_item ) {
if ( ! isset( $checked_map[ $cart_key ] ) ) {
$to_remove[] = $cart_key;
}
}
// 5) Remove
foreach ( $to_remove as $cart_key ) {
WC()->cart->remove_cart_item( $cart_key );
}
// 6) Recalculate totals + persist
WC()->cart->calculate_totals();
WC()->cart->set_session();
if ( isset( WC()->session ) && method_exists( WC()->session, 'save_data' ) ) {
WC()->session->save_data();
}
// 7) Remove invalid coupons (optional safety)
$applied_coupons = WC()->cart->get_applied_coupons();
foreach ( $applied_coupons as $coupon_code ) {
try {
$coupon = new WC_Coupon( $coupon_code );
// If coupon object exists but is invalid, remove
if ( method_exists( $coupon, 'is_valid' ) && ! $coupon->is_valid() ) {
WC()->cart->remove_coupon( $coupon_code );
}
} catch ( Throwable $e ) {
WC()->cart->remove_coupon( $coupon_code );
}
}
// Recalculate again after coupon changes
WC()->cart->calculate_totals();
WC()->cart->set_session();
if ( isset( WC()->session ) && method_exists( WC()->session, 'save_data' ) ) {
WC()->session->save_data();
}
wp_send_json_success( [ 'message' => 'Cart updated' ] );
}
/* ---------------------------------------
Replace "Order total" with selected total placeholder (cart only)
---------------------------------------- */
add_filter( 'woocommerce_cart_totals_order_total_html', function ( $value ) {
if ( is_cart() ) {
return '<span id="selected-total">0 р.</span>';
}
return $value;
} );Добавьте js в дочернюю тему, создайте папку js
../public_html/wp-content/themes/hello-elementor-child/js/cart-checkbox-selection.js
Файл cart-checkbox-selection.js
jQuery(function ($) {
const $doc = $(document);
const $body = $(document.body);
const parsePrice = (str) =>
parseFloat(String(str).replace(/[^\d.,]/g, "").replace(",", ".")) || 0;
const stopScroll = () => {
[0, 40, 120, 240, 400].forEach(t =>
setTimeout(() => $("html, body").stop(), t)
);
};
/* -------------------------
АНИМАЦИЯ СТРОКИ ТОВАРА
---------------------------- */
function breathRow($row) {
$row.addClass("cart-row-breath");
}
function stopBreathRow($row) {
$row.removeClass("cart-row-breath");
}
/* ----------------------------------------------------
ГЛОБАЛЬНЫЙ СПИННЕР ТОЛЬКО В БЛОКЕ "ИТОГО"
------------------------------------------------------ */
function showTotalsLoader() {
if (!$(".cart-collaterals").length) return;
// не плодим
if ($(".totals-loader-overlay").length) return;
$(".cart-collaterals").append(`
<div class="totals-loader-overlay"></div>
<div class="totals-loader-spinner"></div>
`);
}
function hideTotalsLoader() {
$(".totals-loader-overlay, .totals-loader-spinner").remove();
}
/* ---------- PLUS / MINUS -------- */
function updateQuantityButtons() {
$("input.qty").each(function () {
const $input = $(this);
const $wrap = $input.parent();
const max = parseFloat($input.attr("max"));
const min = parseFloat($input.attr("min"));
if (max === 1 && min === 1) {
$wrap.find("button.plus, button.minus").hide();
} else {
$wrap.find("button.plus, button.minus").show();
}
});
}
$doc.on("click", "button.plus, button.minus", function () {
const $row = $(this).closest(".woocommerce-cart-form__cart-item");
breathRow($row);
const $input = $row.find(".qty");
let val = parseFloat($input.val());
const max = parseFloat($input.attr("max"));
const min = parseFloat($input.attr("min"));
const step = parseFloat($input.attr("step")) || 1;
if ($(this).hasClass("plus")) {
val = max && val >= max ? max : val + step;
} else {
val = min && val <= min ? min : val - step;
}
$input.val(val).trigger("change");
});
$(".woocommerce").on("change", ".qty", function () {
const $row = $(this).closest(".woocommerce-cart-form__cart-item");
breathRow($row);
$("[name='update_cart']").prop("disabled", false).trigger("click");
});
/* ----------- CHECKOUT BUTTON ----------- */
function updateCheckoutButton() {
const $btn = $(".checkout-button");
if (!$btn.length) return;
const sum = parsePrice($("#selected-total").text());
let totalQty = 0;
$(".cart-item-checkbox:checked").each(function () {
const qty = parseFloat(
$(this).closest(".woocommerce-cart-form__cart-item").find(".qty").val()
) || 0;
totalQty += qty;
});
if (sum > 0 && totalQty > 0) {
$btn.html(`
К оформлению
<div class="checkout-summary">${totalQty} шт., ${sum} р.</div>
`);
} else {
$btn.html("К оформлению");
}
}
/* ----------- TOTAL CALCULATION (Woo standard prices) ----------- */
function getRowLineSubtotal($row) {
// Стандартно Woo кладёт сумму строки (цена * qty) сюда:
const $sub = $row.find(".product-subtotal .amount").first();
if ($sub.length) return parsePrice($sub.text());
// Фолбэк: (цена за единицу * qty)
const qty = parseFloat($row.find(".qty").val()) || 0;
const unitPriceText =
$row.find(".product-price .amount").first().text() ||
$row.find(".amount").first().text();
return (parsePrice(unitPriceText) * qty) || 0;
}
function recalcSelectedTotal() {
let selectedRaw = 0;
let allRaw = 0;
// subtotal/discount из totals (как у Woo), чтобы учесть купоны пропорционально
const subtotal = parsePrice($(".cart-subtotal .amount").first().text());
const discount = parsePrice($(".cart-discount .amount").first().text());
const wcTotal = subtotal - discount;
const discountRatio = subtotal ? wcTotal / subtotal : 1;
$(".woocommerce-cart-form__cart-item").each(function () {
const $row = $(this);
const rowLineSubtotal = getRowLineSubtotal($row);
allRaw += rowLineSubtotal;
if ($row.find(".cart-item-checkbox").prop("checked")) {
selectedRaw += rowLineSubtotal;
}
});
// Если выбрано всё — показываем итог Woo после купона.
// Если выбрана часть — применяем скидку пропорционально.
let finalTotal =
!selectedRaw ? 0 :
selectedRaw === allRaw ? wcTotal :
selectedRaw * discountRatio;
// защита от -0 и отрицательных значений
if (!isFinite(finalTotal) || finalTotal < 0) finalTotal = 0;
$("#selected-total").text(finalTotal.toFixed(0) + " р.");
updateCheckoutButton();
}
/* ----------- CHECKBOXES ----------- */
function insertCartCheckboxes() {
$(".woocommerce-cart-form__cart-item").each(function () {
const $row = $(this);
if ($row.find(".cart-item-checkbox").length) return;
const input = $row.find("input.qty").attr("name");
if (!input) return;
const m = input.match(/\[(.*?)\]/);
if (!m) return;
const key = m[1];
$row.prepend(`
<td class="product-select">
<input type="checkbox" class="cart-item-checkbox" value="${key}" checked>
</td>
`);
});
if (!$(".select-all-wrapper").length) {
$(".shop_table thead tr").prepend(`
<th class="product-select">
<div class="select-all-wrapper">
<input type="checkbox" id="cart-select-all" checked>
<label for="cart-select-all" class="select-all-text">Выбрать всё</label>
</div>
</th>
`);
}
}
function updateSelectAll() {
const total = $(".cart-item-checkbox").length;
const checked = $(".cart-item-checkbox:checked").length;
$("#cart-select-all").prop("checked", total > 0 && total === checked);
}
/* ----------- CART UPDATE ----------- */
function afterCartUpdate() {
// выключаем дыхание сразу после перерисовки Woo
$(".cart-row-breath").removeClass("cart-row-breath");
hideTotalsLoader();
insertCartCheckboxes();
updateQuantityButtons();
updateSelectAll();
recalcSelectedTotal();
updateCheckoutButton();
stopScroll();
}
afterCartUpdate();
/* -------------------------
HOOKS
---------------------------- */
$body.on("updated_cart_totals", afterCartUpdate);
$body.on("applied_coupon removed_coupon", function () {
showTotalsLoader();
setTimeout(afterCartUpdate, 300);
});
/* --- удаление товара — дыхание строки товара --- */
$doc.on("click", ".product-remove a", function () {
const $row = $(this).closest("tr");
breathRow($row);
});
$doc.on("change", ".cart-item-checkbox", function () {
updateSelectAll();
recalcSelectedTotal();
});
$doc.on("change", "#cart-select-all", function () {
$(".cart-item-checkbox").prop("checked", this.checked);
recalcSelectedTotal();
});
/* ----------- CHECKOUT ----------- */
$doc.on("click", ".checkout-button", function (e) {
const checked = $(".cart-item-checkbox:checked")
.map(function () { return $(this).val(); })
.get();
if (!checked.length) {
alert("Выберите хотя бы один товар!");
return false;
}
// опционально: проверка класса недоступности (оставил как у вас)
let hasUnavailable = false;
$(".cart-item-checkbox:checked").each(function () {
const $row = $(this).closest(".woocommerce-cart-form__cart-item");
if ($row.hasClass("avs-outofstock-item")) {
hasUnavailable = true;
return false;
}
});
if (hasUnavailable) {
alert("В заказе есть товары, которые недоступны к оформлению");
return false;
}
e.preventDefault();
showTotalsLoader();
$.post(my_cart_select.ajaxurl, {
action: "remove_unchecked_cart_items",
checked,
nonce: my_cart_select.nonce
}, () => window.location.href = "/checkout");
});
});
И самое сложно это css. Ниже код для анимации:
/* Отключить стандарт анимацию*/
.woocommerce .blockUI.blockOverlay:before,
.woocommerce .loader:before {
display: none !important;
content: none !important;}
.blockUI.blockOverlay {
background: transparent !important;
opacity: 0 !important;
pointer-events: none !important;}
/* своя анимация */
.totals-loader-overlay {
position: absolute;
inset: 0;
background: rgba(255,255,255,0.35);
z-index: 50;}
.totals-loader-spinner {
position: absolute;
top: 50%;
left: 50%;
width: 32px;
height: 32px;
border: 4px solid #6A6A6A;
border-right-color: transparent;
border-radius: 50%;
animation: woospin 0.6s linear infinite;
transform: translate(-50%, -50%);
z-index: 60;}
@keyframes woospin {
0% { transform: translate(-50%, -50%) rotate(0deg); }
100% { transform: translate(-50%, -50%) rotate(360deg); }}
/* Анимация мигание */
.cart-row-breath {animation: cartBreathing 1.3s ease-in-out infinite;}
@keyframes cartBreathing {
0% { opacity: 1; }
30% { opacity: 0.6; }
60% { opacity: 0.85; }
100% { opacity: 1; }}
/* Отключить уведомления */
.woocommerce-notices-wrapper{display:none!important;}И css визуально для корзины:
.cart-subtotal{display:none;}
tr.cart-subtotal, .cart_totals h2, .product-price{display:none!important;}
table.cart img{aspect-ratio:1/1;object-fit: cover;border-radius:8px;border:1px solid#C5C5C5;}
.remove{padding:4px;}
/*кол-во*/
input::-webkit-inner-spin-button{display:none;}
selector .input-text.qty {text-align:center;width:38px;}
.quantity{background-color:#D2DEE8; padding:2px;border-radius:8px;text-align:center;display: inline-flex; align-items:end; justify-content: center;}
selector .minus,selector .plus{background-color:transparent;font-size: 22px;padding:1px 9px;border-radius:8px;font-family: YS Text,Helvetica,Arial,sans-serif;color:#000;border:none;font-weight:500;}
.shop_table_responsive tr td, .woocommerce-page table.shop_table_responsive tr td{text-align:left!important;}
tr.selected-total-row{background-color:#fff;}
.woocommerce-page table.shop_table_responsive thead {display: table-header-group;}
#selected-total{font-size:18px;color:#000;}
tr.order-total ::before{font-weight:bold!important;font-size:18px!important;}
/*чекбоксы*/
.cart-item-checkbox, #cart-select-all {
appearance: none;
-webkit-appearance: none;
outline: none;
width: 22px;
height: 22px;
border: 2px solid #b3b3b3;
border-radius:6px;
background: #E4EBF1;
cursor: pointer;
position: relative;
vertical-align: top;}
.cart-item-checkbox:checked, #cart-select-all:checked {
background: #89ADE0;
border-color: #89ADE0;}
.cart-item-checkbox:checked::after,
#cart-select-all:checked::after {
content: '';
display: block;
position: absolute;
left: 6px;
top: 3px;
width: 6px;
height: 10px;
border: solid #fff;
border-width: 0 3px 3px 0;
transform: rotate(45deg);}
/*К оформлению*/
.checkout-button .checkout-summary {font-size:13px;opacity: 0.9;margin-top:3px;font-weight:500;}
/*выбрать всё*/
.select-all-wrapper {
position: relative;
width: 22px;
height: 22px;}
.select-all-text {
position: absolute;
left: 36px;
top: 50%;
transform: translateY(-50%);
white-space: nowrap;
cursor: pointer;
font-size: 14px;
margin: 0;}
/*для компов*/
@media (min-width: 1200px){
.product-remove {font-size:20px!important;width:26px;} .product-name {text-align:left;} .product-quantity {width:136px;} table.cart img {width:120px!important;} .product-thumbnail{width:140px;}.shop_table {border-spacing:0 8px;}
td.product-select {position: relative; width: 1px;}
.cart-item-checkbox {position: absolute;top: 12px; left: 12px;}
td.product-select,th.product-select{padding-left:12px!important;max-width:20px;}}
@media (min-width: 961px) and (max-width: 1199px) {.product-remove {font-size:20px!important;width:20px;} .product-quantity {width:136px;} .product-subtotal {width:40px;}table.cart img {width:60px!important;} .product-thumbnail{width:80px;}.shop_table {border-spacing:0 8px;}
td.product-select {position: relative; width: 1px;}
.cart-item-checkbox {position: absolute;top: 12px; left: 12px;}
td.product-select,th.product-select{padding-left:12px!important;max-width:20px;}}
@media (min-width: 769px) and (max-width: 960px) {selector .product-remove {font-size:20px!important;width:20px; text-align:left!important;} selector .product-thumbnail {width:65px;} selector .product-quantity {width:150px;} selector .product-subtotal {width:70px; text-align:center;}selector table.cart img {width:150px;} selector .product-thumbnail{width:150px;}.shop_table {border-spacing:0 8px;}
td.product-select {position: relative; width: 1px;}
.cart-item-checkbox {position: absolute;top: 12px; left: 12px;}
td.product-select,th.product-select{padding-left:12px!important;max-width:20px;}}
/*для мобилок*/
@media (max-width: 768px) {
th.product-name, th.product-quantity, th.product-subtotal{display:none;}
.cart td:before{display:none;}
span.woocommerce-Price-amount{font-size: 13px!important;}
.cart tr{background-color:#E4EBF1;border-radius:14px;margin-bottom:8px;}
.quantity {width:118px;}
.qty {width:44px!important;}
.wc-proceed-to-checkout {position: fixed;
bottom: 54px;left: 24px;right: 24px; z-index: 999;}
.woocommerce table.cart,
.woocommerce table.cart tbody {width: 100%;}
.woocommerce table.cart tr.woocommerce-cart-form__cart-item.cart_item {
display: block;
position: relative;
padding: 12px 12px 16px 12px;
margin-bottom: 10px;
background: #E4EBF1;
border-radius: 12px;}
.woocommerce table.cart td.product-thumbnail {
display: block !important;
float: left;
width: 90px !important;
padding: 0 !important;
margin-right: 12px;
flex: none;}
.woocommerce table.cart td.product-thumbnail img {
width: 90px !important;
object-fit: cover;
border-radius: 10px;
display: block;}
.woocommerce table.cart td.product-name,
.woocommerce table.cart td.product-quantity,
.woocommerce table.cart td.product-subtotal {
display: block !important;
margin-left: 100px;
padding: 0 !important;
clear: none;}
.woocommerce table.cart td.product-quantity {
margin-top: 11px;}
.woocommerce table.cart td.product-quantity .quantity {
margin: 0;}
.woocommerce table.cart td.product-subtotal {
margin-top: 4px;}
.woocommerce table.cart td.product-remove {
position: absolute;
right: 12px;
top: 0px;
width: auto;
z-index: 10;
display: block;}
.woocommerce table.cart td.product-remove .remove {
font-size: 30px;}
/* Очистка float после каждой строки */
.woocommerce table.cart tr.woocommerce-cart-form__cart-item.cart_item::after {
content: "";
display: block;
clear: both;}}
@media (max-width: 480px){.wc-proceed-to-checkout{bottom:43px;left:4px;right: 4px;}}
.elementor-widget-woocommerce-cart .woocommerce table.cart tr{padding:16px 12px;}
/* Строки товаров*/
tr.woocommerce-cart-form__cart-item.cart_item{background:#E4EBF1;}
.woocommerce-cart-form__cart-item td:first-child {border-top-left-radius: 14px;
border-bottom-left-radius: 14px;}
.woocommerce-cart-form__cart-item td:last-child {border-top-right-radius: 14px;
border-bottom-right-radius: 14px;}
Настройки для компа и мобилки.
Слева — для компа.
Типография


Итог заказа


Итого


Настроить: сводка заказов
одинаково для компа и мобилки

Настроить: Итоги


Также в корзине, если применён купон, то его условия проверяются при нажатии на кнопку «Перейти к оформлению», так как чекбоксами можно отметить меньше товаров и это нарушит условия купона.