ajax自动更新购物车总数量,WooCommerce - Ajax添加到购物车并更新总计

在开发一个允许用户从主页添加产品到购物车的网站时,遇到购物车总数不自动更新的问题。尝试了WooCommerce的cpp_header_add_to_cart_fragment函数,以及已弃用的add_to_cart_fragments和推荐的woocommerce_add_to_cart_fragments,但均未成功。代码中包含了PHP和JavaScript部分,使用Ajax进行产品添加,并尝试通过过滤器和动作来更新购物车数量,但目前Ajax调用返回的片段未正确替换显示购物车总数的HTML。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

我正在开发一个网站,允许用户从主页上将产品添加到购物车.我从他们的网站和其他SO问题在线跟踪了一些资源,这些问题允许我通过Ajax将产品添加到购物车,但是如果没有页面重新加载,购物车总数将不会更新.

WooCommerce的文档是cpp_header_add_to_cart_fragment函数的来源,它似乎根本不起作用.最初我在使用,add_to_cart_fragments但我发现它已被弃用,我应该使用,woocommerce_add_to_cart_fragments但这种改变也无济于事.

我读的代码越多......我注意到片段是从ajax调用开始返回的,所以我开始认为我需要用javascript返回的内容替换显示购物车总数的html?

page_home.php

<?php echo WC()->cart->get_cart_total(); ?>

的functions.php

add_action('wp_enqueue_scripts', 'cpp_enqueue_scripts');

function cpp_enqueue_scripts() {

/* Other enqueue/registers */

wp_register_script('diy_kits', get_template_directory_uri().'/js/diy_kit.js');

wp_enqueue_script('diy_kits');

wp_localize_script(

'diy_kits',

'cpp_ajax',

array(

'ajaxurl' => admin_url('admin-ajax.php'),

'diy_product_nonce' => wp_create_nonce('diy_product_nonce')

)

);

}

add_action('wp_ajax_nopriv_cpp_ajax-submit', 'cpp_ajax_submit');

add_action('wp_ajax_cpp_ajax-submit', 'cpp_ajax_submit');

function cpp_ajax_submit() {

global $woocommerce;

$nonce = $_POST['nonce'];

if(!wp_verify_nonce($nonce, 'diy_product_nonce')) {

wp_die('Busted!');

}

// Add product to cart... this works

$product_id = $_POST['product_id'];

if( $woocommerce->cart->add_to_cart( $product_id ) ) {

$data = apply_filters('woocommerce_add_to_cart_fragments', array());

do_action('woocommerce_ajax_added_to_cart', $product_id);

} else {

$data = array( 'success' => false, 'product_id' => $product_id );

}

$response = json_encode($data);

header("Content-Type: application/json");

echo $response;

exit;

}

cpp_header_add_to_cart_fragment

// CART UPDATE AJAX this doesn't work

add_filter('woocommerce_add_to_cart_fragments', 'cpp_header_add_to_cart_fragment');

function cpp_header_add_to_cart_fragment( $fragments ) {

global $woocommerce;

ob_start(); ?>

<?php echo WC()->cart->get_cart_total(); ?>

$fragments['a.cart-contents'] = ob_get_clean();

return $fragments;

}

diy_kits.js

// setup and other stuff...

links.click(function(e) {

/* unrelated stuff */

jQuery.post(

cpp_ajax.ajaxurl,

{

action : 'cpp_ajax-submit',

nonce : cpp_ajax.diy_product_nonce,

product_id : jQuery(this).attr('data-product-id')

},

function(response) {

console.log(response);

}

);

});

This is the full code in my cart.php <?php /** * Custom Cart Page for WooCommerce with Selective Checkout * Place this file in your child theme directory: /wp-content/themes/woodmart-child/cart.php */ if (!defined('ABSPATH')) { exit; // Exit if accessed directly } do_action('woocommerce_before_cart'); ?> <div class="cart-page-section container" style="max-width: 1200px; margin: 0 auto;"> <form class="woocommerce-cart-form" action="<?php echo esc_url(wc_get_cart_url()); ?>" method="post"> <?php do_action('woocommerce_before_cart_table'); ?> <table class="shop_table shop_table_responsive cart woocommerce-cart-form__contents"> <thead> <tr> <th class="product-select"> <input type="checkbox" id="select-all-items" /> <label for="select-all-items" style="display: inline-block; margin-left: 5px; cursor: pointer;">全选</label> </th> <th class="product-info"><?php esc_html_e('Product', 'woocommerce'); ?></th> <th class="product-params"><?php esc_html_e('Parameters', 'woocommerce'); ?></th> <th class="product-price"><?php esc_html_e('Price', 'woocommerce'); ?></th> <th class="product-quantity"><?php esc_html_e('Quantity', 'woocommerce'); ?></th> <th class="product-subtotal"><?php esc_html_e('Subtotal', 'woocommerce'); ?></th> <!-- 已移除 Action 列 --> </tr> </thead> <tbody> <?php do_action('woocommerce_before_cart_contents'); ?> <?php foreach (WC()->cart->get_cart() as $cart_item_key => $cart_item) : $_product = apply_filters('woocommerce_cart_item_product', $cart_item['data'], $cart_item, $cart_item_key); $product_id = apply_filters('woocommerce_cart_item_product_id', $cart_item['product_id'], $cart_item, $cart_item_key); if ($_product && $_product->exists() && $cart_item['quantity'] > 0 && apply_filters('woocommerce_cart_item_visible', true, $cart_item, $cart_item_key)) : $product_permalink = apply_filters('woocommerce_cart_item_permalink', $_product->is_visible() ? $_product->get_permalink($cart_item) : '', $cart_item, $cart_item_key); ?> <tr class="woocommerce-cart-form__cart-item <?php echo esc_attr(apply_filters('woocommerce_cart_item_class', 'cart_item', $cart_item, $cart_item_key)); ?>"> <!-- Checkbox Column --> <td class="product-select" data-title="<?php esc_attr_e('Select', 'woocommerce'); ?>"> <input type="checkbox" class="item-checkbox" name="selected_items[]" value="<?php echo esc_attr($cart_item_key); ?>" data-price="<?php echo esc_attr($cart_item['line_total']); ?>" /> </td> <!-- Product Info Column --> <td class="product-info" data-title="<?php esc_attr_e('Product', 'woocommerce'); ?>"> <div class="product-image"> <?php $thumbnail = apply_filters('woocommerce_cart_item_thumbnail', $_product->get_image(), $cart_item, $cart_item_key); if (!$product_permalink) : echo $thumbnail; // PHPCS: XSS ok. else : printf('<a href="%s">%s</a>', esc_url($product_permalink), $thumbnail); // PHPCS: XSS ok. endif; ?> </div> <div class="product-name"> <?php if (!$product_permalink) : echo wp_kses_post(apply_filters('woocommerce_cart_item_name', $_product->get_name(), $cart_item, $cart_item_key) . ' '); else : echo wp_kses_post(apply_filters('woocommerce_cart_item_name', sprintf('<a href="%s">%s</a>', esc_url($product_permalink), $_product->get_name()), $cart_item, $cart_item_key)); endif; do_action('woocommerce_after_cart_item_name', $cart_item, $cart_item_key); // Meta data. echo wc_get_formatted_cart_item_data($cart_item); // PHPCS: XSS ok. ?> </div> </td> <!-- Product Parameters Column --> <td class="product-params" data-title="<?php esc_attr_e('Parameters', 'woocommerce'); ?>"> <?php if ($cart_item['variation_id']) { $variation_attributes = $_product->get_variation_attributes(); if (!empty($variation_attributes)) { foreach ($variation_attributes as $attribute => $value) { echo '<span class="param">' . esc_html(wc_attribute_label($attribute)) . ': ' . esc_html($value) . '</span><br>'; } } } else { $attributes = $_product->get_attributes(); if (!empty($attributes)) { foreach ($attributes as $attribute) { $values = wc_get_product_terms($product_id, $attribute['name'], array('fields' => 'names')); echo '<span class="param">' . esc_html(wc_attribute_label($attribute['name'])) . ': ' . esc_html(implode(', ', $values)) . '</span><br>'; } } } ?> </td> <!-- Price Column --> <td class="product-price" data-title="<?php esc_attr_e('Price', 'woocommerce'); ?>"> <?php echo apply_filters('woocommerce_cart_item_price', WC()->cart->get_product_price($_product), $cart_item, $cart_item_key); // PHPCS: XSS ok. ?> </td> <!-- Quantity Column --> <td class="product-quantity" data-title="<?php esc_attr_e('Quantity', 'woocommerce'); ?>"> <?php if ($_product->is_sold_individually()) : $product_quantity = sprintf('1 <input type="hidden" name="cart[%s][qty]" value="1" />', $cart_item_key); else : $product_quantity = woocommerce_quantity_input( array( 'input_name' => "cart[{$cart_item_key}][qty]", 'input_value' => $cart_item['quantity'], 'max_value' => $_product->get_max_purchase_quantity(), 'min_value' => '0', 'product_name' => $_product->get_name(), ), $_product, false ); endif; echo apply_filters('woocommerce_cart_item_quantity', $product_quantity, $cart_item_key, $cart_item); // PHPCS: XSS ok. ?> </td> <!-- Subtotal Column --> <td class="product-subtotal" data-title="<?php esc_attr_e('Subtotal', 'woocommerce'); ?>"> <?php echo apply_filters('woocommerce_cart_item_subtotal', WC()->cart->get_product_subtotal($_product, $cart_item['quantity']), $cart_item, $cart_item_key); // PHPCS: XSS ok. ?> </td> <!-- 已移除 Remove Item Column --> </tr> <?php endif; ?> <?php endforeach; ?> <?php do_action('woocommerce_after_cart_contents'); ?> </tbody> </table> <div class="actions"> <button type="submit" class="button" name="update_cart" value="<?php esc_attr_e('Update cart', 'woocommerce'); ?>"><?php esc_html_e('Update cart', 'woocommerce'); ?></button> <?php do_action('woocommerce_cart_actions'); ?> <?php wp_nonce_field('woocommerce-cart', 'woocommerce-cart-nonce'); ?> </div> <?php do_action('woocommerce_after_cart_table'); ?> </form> </div> <!-- Sticky Footer --> <div class="cart-footer-actions sticky-footer" style="position: sticky; bottom: 0; background: white; padding: 15px; border-top: 1px solid #ddd; max-width: 1200px; margin: 0 auto;"> <div style="display: flex; justify-content: space-between; align-items: center;"> <div> <input type="checkbox" id="footer-select-all"> <label for="footer-select-all" style="display: inline-block; margin-left: 5px; cursor: pointer;">全选</label> <button type="button" class="button" id="remove-selected-items">刪除選中的商品</button> <button type="button" class="button" id="clear-cart">清理購物車</button> </div> <div class="selected-summary" style="text-align: right;"> <p> 已选商品: <span id="selected-count">0</span> 件,共计: <span id="selected-total">RM0.00</span> </p> <a href="<?php echo esc_url(wc_get_checkout_url()); ?>" class="checkout-button button alt wc-forward" id="partial-checkout"> 结算 </a> </div> </div> </div> <?php do_action('woocommerce_after_cart'); ?> <style> /* Custom Styles for Cart Page */ .cart-page-section { background: white; padding: 30px; border-radius: 8px; box-shadow: 0 0 10px rgba(0,0,0,0.1); margin-bottom: 30px; } .cart-page-section table.cart { width: 100%; border-collapse: collapse; margin-bottom: 20px; } .cart-page-section table.cart th, .cart-page-section table.cart td { padding: 15px; text-align: left; border-bottom: 1px solid #eee; } .cart-page-section table.cart th { background-color: #f8f8f8; font-weight: bold; } /* 调整列宽 */ .cart-page-section table.cart td.product-select { width: 10%; text-align: center; vertical-align: middle; } .cart-page-section table.cart td.product-info { width: 20%; vertical-align: top; } .cart-page-section table.cart .product-info .product-image { float: left; margin-right: 15px; width: 100px; height: 100px; } .cart-page-section table.cart .product-info .product-image img { max-width: 100%; height: auto; display: block; } .cart-page-section table.cart .product-info .product-name { overflow: hidden; } .cart-page-section table.cart td.product-params { width: 20%; vertical-align: top; } .cart-page-section table.cart .product-params .param { display: block; margin-bottom: 5px; font-size: 14px; color: #666; } /* 调整剩余列宽度 */ .cart-page-section table.cart td.product-price, .cart-page-section table.cart td.product-quantity, .cart-page-section table.cart td.product-subtotal { width: 16.67%; /* 三列平均分配剩余宽度 */ vertical-align: middle; } .cart-page-section .actions { text-align: right; margin-top: 20px; } .cart-page-section .actions .button { padding: 12px 24px; background-color: #4CAF50; color: white; border: none; border-radius: 4px; cursor: pointer; font-size: 16px; transition: background-color 0.3s; } .cart-page-section .actions .button:hover { background-color: #45a049; } .cart-footer-actions { position: sticky; bottom: 0; background: #fff; padding: 15px; border-top: 1px solid #ddd; box-shadow: 0 -2px 10px rgba(0,0,0,0.1); z-index: 100; } .cart-footer-actions .button { padding: 10px 20px; margin-left: 10px; background-color: #f44336; color: white; border: none; border-radius: 4px; cursor: pointer; font-size: 14px; transition: background-color 0.3s; } .cart-footer-actions .button:hover { background-color: #d32f2f; } #partial-checkout { padding: 12px 24px; background-color: #2196F3; color: white; text-decoration: none; border-radius: 4px; display: inline-block; margin-top: 10px; transition: background-color 0.3s; } #partial-checkout:hover { background-color: #0b7dda; } .selected-summary { font-size: 16px; font-weight: bold; } .selected-summary p { margin: 0 0 10px 0; } /* Responsive styles */ @media (max-width: 768px) { .cart-page-section table.cart thead { display: none; } .cart-page-section table.cart td { display: block; width: 100% !important; text-align: right; padding: 10px; position: relative; padding-left: 50%; } .cart-page-section table.cart td::before { content: attr(data-title); position: absolute; left: 15px; font-weight: bold; text-align: left; } .cart-page-section table.cart .product-info .product-image { float: none; margin: 0 auto 10px; } .cart-footer-actions { position: relative; } .cart-footer-actions > div { flex-direction: column; align-items: flex-start; } .cart-footer-actions .selected-summary { margin-top: 20px; text-align: left; width: 100%; } } </style> <script> jQuery(document).ready(function($) { // Define our AJAX parameters var wc_cart_params = { ajax_url: '<?php echo admin_url('admin-ajax.php'); ?>', cart_nonce: '<?php echo wp_create_nonce('woocommerce-cart'); ?>' }; // Update selected items summary function updateSelectedSummary() { let total = 0; let count = 0; $('.item-checkbox:checked').each(function() { total += parseFloat($(this).data('price')); count++; }); $('#selected-count').text(count); $('#selected-total').text('RM' + total.toFixed(2)); } // Select all functionality $('#select-all-items, #footer-select-all').change(function() { const isChecked = $(this).prop('checked'); $('.item-checkbox').prop('checked', isChecked); updateSelectedSummary(); }); // Individual checkbox change $('.item-checkbox').change(updateSelectedSummary); // Remove selected items $('#remove-selected-items').click(function() { const selectedKeys = $('.item-checkbox:checked').map(function() { return this.value; }).get(); if (selectedKeys.length === 0) { alert('请选择要删除的商品'); return; } if (!confirm('确定要删除选中的商品吗?')) { return; } $.ajax({ type: 'POST', url: wc_cart_params.ajax_url, data: { action: 'remove_selected_cart_items', selected_items: selectedKeys, security: wc_cart_params.cart_nonce }, success: function(response) { if (response.success) { location.reload(); } }, error: function() { alert('删除失败,请重试'); } }); }); // Clear entire cart $('#clear-cart').click(function() { if (!confirm('确定要清空购物车吗?')) { return; } $.ajax({ type: 'POST', url: wc_cart_params.ajax_url, data: { action: 'clear_entire_cart', security: wc_cart_params.cart_nonce }, success: function(response) { if (response.success) { location.reload(); } }, error: function() { alert('清空购物车失败,请重试'); } }); }); // Partial checkout $('#partial-checkout').click(function(e) { e.preventDefault(); const selectedKeys = $('.item-checkbox:checked').map(function() { return this.value; }).get(); if (selectedKeys.length === 0) { alert('请至少选择一件商品结算'); return false; } // Show loading indicator $(this).html('处理中...').prop('disabled', true); // Store selected items in session $.ajax({ type: 'POST', url: wc_cart_params.ajax_url, data: { action: 'store_selected_items', selected_items: selectedKeys, security: wc_cart_params.cart_nonce }, success: function(response) { if (response.success) { window.location.href = '<?php echo esc_url(wc_get_checkout_url()); ?>'; } else { alert('结算失败,请重试'); $('#partial-checkout').html('结算').prop('disabled', false); } }, error: function() { alert('发生错误,请重试'); $('#partial-checkout').html('结算').prop('disabled', false); } }); }); // Initialize summary updateSelectedSummary(); }); </script> This is the full code in my functions.php // 完全删除旧的"部分结账"相关代码 // 替换为以下完整优化版本 // ===== 部分结账功能核心代码 ===== // // 存储选中商品到会话 add_action('wp_ajax_store_selected_items', 'store_selected_items'); add_action('wp_ajax_nopriv_store_selected_items', 'store_selected_items'); function store_selected_items() { check_ajax_referer('woocommerce-cart', 'security'); if (isset($_POST['selected_items'])) { $sanitized_items = array_map('sanitize_text_field', $_POST['selected_items']); WC()->session->set('selected_checkout_items', $sanitized_items); wp_send_json_success(); } wp_send_json_error(); } // 折扣计算前应用购物车过滤 (解决折扣问题) add_action('woocommerce_before_calculate_totals', 'apply_partial_cart_before_discounts', 5); function apply_partial_cart_before_discounts() { if (!is_checkout() || is_wc_endpoint_url('order-received') || !WC()->session) { return; } $selected_items = WC()->session->get('selected_checkout_items'); if (!empty($selected_items)) { $cart = WC()->cart; $cart_contents = $cart->cart_contents; $filtered_contents = array(); foreach ($cart_contents as $key => $item) { if (in_array($key, $selected_items)) { $filtered_contents[$key] = $item; } } $cart->cart_contents = $filtered_contents; } } // 结账页面显示过滤 add_filter('woocommerce_get_cart_contents', 'filter_cart_contents_for_checkout', 20, 1); function filter_cart_contents_for_checkout($cart_contents) { if (is_checkout() && !is_wc_endpoint_url('order-received') && WC()->session) { $selected_items = WC()->session->get('selected_checkout_items'); if (!empty($selected_items)) { $filtered_contents = array(); foreach ($cart_contents as $key => $item) { if (in_array($key, $selected_items)) { $filtered_contents[$key] = $item; } } return $filtered_contents; } } return $cart_contents; } // 结账后恢复购物车 add_action('woocommerce_checkout_update_order_meta', 'restore_full_cart_after_checkout', 10, 2); function restore_full_cart_after_checkout($order_id, $data) { if (!WC()->session) return; // 备份完整购物车 $full_cart = WC()->cart->get_cart(); WC()->session->set('full_cart_backup', $full_cart); } // 订单感谢页处理 add_action('woocommerce_thankyou', 'remove_selected_items_after_checkout', 10, 1); function remove_selected_items_after_checkout($order_id) { if (!WC()->session) return; $selected_items = WC()->session->get('selected_checkout_items'); if (!empty($selected_items)) { // 恢复完整购物车 $full_cart = WC()->session->get('full_cart_backup'); if ($full_cart) { WC()->cart->cart_contents = $full_cart; WC()->session->__unset('full_cart_backup'); } WC()->session->__unset('selected_checkout_items'); WC()->cart->calculate_totals(); } } // AJAX移除选中商品 add_action('wp_ajax_remove_selected_cart_items', 'remove_selected_cart_items'); add_action('wp_ajax_nopriv_remove_selected_cart_items', 'remove_selected_cart_items'); function remove_selected_cart_items() { check_ajax_referer('woocommerce-cart', 'security'); if (isset($_POST['selected_items'])) { foreach ($_POST['selected_items'] as $cart_item_key) { $sanitized_key = sanitize_text_field($cart_item_key); if (WC()->cart->get_cart_item($sanitized_key)) { WC()->cart->remove_cart_item($sanitized_key); } } wp_send_json_success(); } wp_send_json_error(); } // 覆盖购物车清空方法 add_action('woocommerce_init', 'override_woocommerce_cart'); function override_woocommerce_cart() { if (!class_exists('WC_Cart') || !WC()->session) return; class WC_Cart_Custom extends WC_Cart { public function empty_cart($force_session = false) { if (WC()->session && WC()->session->get('selected_checkout_items')) { return; // 阻止清空 } parent::empty_cart($force_session); } } $GLOBALS['woocommerce']->cart = new WC_Cart_Custom(); } // ===== 辅助功能 ===== // // 移除购物车总计部分 add_action('template_redirect', 'remove_cart_totals_section'); function remove_cart_totals_section() { if (is_cart()) { remove_action('woocommerce_cart_collaterals', 'woocommerce_cart_totals', 10); } } // 加载必要脚本 add_action('wp_enqueue_scripts', 'partial_checkout_scripts'); function partial_checkout_scripts() { if (is_cart()) { wp_enqueue_script('wc-cart'); wp_localize_script('wc-cart', 'wc_cart_params', array( 'ajax_url' => admin_url('admin-ajax.php'), 'cart_nonce' => wp_create_nonce('woocommerce-cart') )); } } // 放弃结账时恢复原始购物车 add_action('template_redirect', 'restore_original_cart_if_abandoned'); function restore_original_cart_if_abandoned() { if (is_cart() && WC()->session && WC()->session->get('selected_checkout_items')) { WC()->session->__unset('selected_checkout_items'); } } the dynamic discount is not applied, Without changing the 成功了的 function, please check which part goes wrong and give me the full code to be replaced with the current one.
08-01
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值