cart)) {
WC()->cart = new WC_Cart();
}
}
}
/**
* 获取当前购物车的快照
*/
function pc_snapshot_current_cart() {
if (!WC()->cart) wc_load_cart();
$items = array();
foreach (WC()->cart->get_cart() as $ci_key => $ci) {
$pid = isset($ci['product_id']) ? (int)$ci['product_id'] : 0;
$vid = isset($ci['variation_id']) ? (int)$ci['variation_id'] : 0;
$qty = isset($ci['quantity']) ? wc_stock_amount($ci['quantity']) : 0;
$var = isset($ci['variation']) && is_array($ci['variation']) ? $ci['variation'] : array();
if ($pid && $qty > 0) {
$items[] = array(
'product_id' => $pid,
'variation_id' => $vid,
'variation' => array_map('wc_clean', $var),
'quantity' => $qty,
);
}
}
return $items;
}
/**
* 从快照恢复购物车
*/
function pc_restore_cart_from_items($items) {
if (!WC()->cart) wc_load_cart();
WC()->cart->empty_cart();
foreach ((array)$items as $it) {
$pid = isset($it['product_id']) ? (int)$it['product_id'] : 0;
$vid = isset($it['variation_id']) ? (int)$it['variation_id'] : 0;
$qty = isset($it['quantity']) ? wc_stock_amount($it['quantity']) : 0;
$var = isset($it['variation']) && is_array($it['variation']) ? array_map('wc_clean', $it['variation']) : array();
if ($pid && $qty > 0) {
WC()->cart->add_to_cart($pid, $qty, $vid, $var);
}
}
WC()->cart->calculate_totals();
}
/**
* 生成瞬态键名
*/
function pc_transient_key($token) {
return 'pc_partial_payload_' . sanitize_key($token);
}
/**
* 构建商品项唯一键
*/
function pc_build_item_key($product_id, $variation_id = 0) {
return $product_id . '_' . $variation_id;
}
/**
* 获取购物车用户标识
*/
function pc_get_cart_uid() {
if (is_user_logged_in()) {
return 'user_' . get_current_user_id();
} else {
if (empty($_COOKIE['pc_cart_uid'])) {
$token = wp_generate_uuid4();
setcookie('pc_cart_uid', $token, time() + YEAR_IN_SECONDS, COOKIEPATH ?: '/', '', is_ssl(), false);
$_COOKIE['pc_cart_uid'] = $token;
}
return 'guest_' . sanitize_text_field(wp_unslash($_COOKIE['pc_cart_uid']));
}
}
/* -------------------------------------------------
* AJAX: 当购物车为空时恢复购物车
* ------------------------------------------------- */
add_action('wp_ajax_pc_rehydrate_cart', 'pc_rehydrate_cart');
add_action('wp_ajax_nopriv_pc_rehydrate_cart', 'pc_rehydrate_cart');
function pc_rehydrate_cart() {
check_ajax_referer('woocommerce-cart', 'security');
$raw = isset($_POST['items']) ? wp_unslash($_POST['items']) : '';
$items = is_string($raw) ? json_decode($raw, true) : (array)$raw;
if (!is_array($items)) {
wp_send_json_error(array('message' => '无效的商品数据'), 400);
}
if (!WC()->cart) wc_load_cart();
if (!WC()->cart->is_empty()) {
wp_send_json_success(array('message' => '购物车非空'));
}
foreach ($items as $it) {
$pid = isset($it['product_id']) ? (int)$it['product_id'] : 0;
$vid = isset($it['variation_id']) ? (int)$it['variation_id'] : 0;
$qty = isset($it['quantity']) ? wc_stock_amount($it['quantity']) : 0;
$var = isset($it['variation']) && is_array($it['variation']) ? array_map('wc_clean', $it['variation']) : array();
if ($pid && $qty > 0) {
WC()->cart->add_to_cart($pid, $qty, $vid, $var);
}
}
WC()->cart->calculate_totals();
wp_send_json_success(array('rehydrated' => true));
}
/* -------------------------------------------------
* AJAX: 更新商品数量 (无需刷新页面)
* ------------------------------------------------- */
add_action('wp_ajax_update_cart_item_qty', 'pc_update_cart_item_qty');
add_action('wp_ajax_nopriv_update_cart_item_qty', 'pc_update_cart_item_qty');
function pc_update_cart_item_qty() {
check_ajax_referer('woocommerce-cart', 'security');
$key = isset($_POST['cart_item_key']) ? wc_clean(wp_unslash($_POST['cart_item_key'])) : '';
$qty = isset($_POST['qty']) ? wc_stock_amount($_POST['qty']) : null;
if (!$key || $qty === null) {
wp_send_json_error(array('message' => '缺少参数'), 400);
}
if (!WC()->cart) wc_load_cart();
if ($qty <= 0) {
$removed = WC()->cart->remove_cart_item($key);
WC()->cart->calculate_totals();
wp_send_json_success(array('removed' => (bool)$removed));
} else {
$set = WC()->cart->set_quantity($key, $qty, true);
WC()->cart->calculate_totals();
$cart_item = WC()->cart->get_cart_item($key);
if (!$cart_item) {
wp_send_json_error(array('message' => '更新后找不到商品'), 404);
}
$_product = $cart_item['data'];
$subtotal_html = apply_filters('woocommerce_cart_item_subtotal', WC()->cart->get_product_subtotal($_product, $cart_item['quantity']), $cart_item, $key);
$line_total_incl_tax = (float)($cart_item['line_total'] + $cart_item['line_tax']);
wp_send_json_success(array(
'subtotal_html' => $subtotal_html,
'line_total_incl_tax' => $line_total_incl_tax,
'removed' => false
));
}
}
/* -------------------------------------------------
* AJAX: 删除选中商品
* ------------------------------------------------- */
add_action('wp_ajax_remove_selected_cart_items', 'pc_remove_selected_cart_items');
add_action('wp_ajax_nopriv_remove_selected_cart_items', 'pc_remove_selected_cart_items');
function pc_remove_selected_cart_items() {
check_ajax_referer('woocommerce-cart', 'security');
$keys = isset($_POST['selected_items']) ? (array) $_POST['selected_items'] : array();
if (!WC()->cart) wc_load_cart();
foreach ($keys as $k) {
$k = wc_clean(wp_unslash($k));
WC()->cart->remove_cart_item($k);
}
WC()->cart->calculate_totals();
wp_send_json_success(true);
}
/* -------------------------------------------------
* AJAX: 清空购物车
* ------------------------------------------------- */
add_action('wp_ajax_empty_cart', 'pc_empty_cart');
add_action('wp_ajax_nopriv_empty_cart', 'pc_empty_cart');
function pc_empty_cart() {
check_ajax_referer('woocommerce-cart', 'security');
if (!WC()->cart) wc_load_cart();
WC()->cart->empty_cart();
wp_send_json_success(true);
}
/* -------------------------------------------------
* AJAX: 应用优惠券
* ------------------------------------------------- */
add_action('wp_ajax_apply_coupon', 'pc_apply_coupon');
add_action('wp_ajax_nopriv_apply_coupon', 'pc_apply_coupon');
function pc_apply_coupon() {
check_ajax_referer('woocommerce-cart', 'security');
$code = isset($_POST['coupon_code']) ? wc_format_coupon_code(wp_unslash($_POST['coupon_code'])) : '';
if (!$code) {
wp_send_json_error(array('message' => __('请输入优惠券代码', 'woocommerce')), 400);
}
if (!WC()->cart) wc_load_cart();
$applied = WC()->cart->apply_coupon($code);
WC()->cart->calculate_totals();
if (is_wp_error($applied)) {
wp_send_json_error(array('message' => $applied->get_error_message()), 400);
}
if (!$applied) {
wp_send_json_error(array('message' => __('优惠券应用失败', 'woocommerce')), 400);
}
wp_send_json_success(true);
}
/* -------------------------------------------------
* AJAX: 创建部分结算订单
* - 将快照和选中商品存储在瞬态中
* - 将会话中的token标记
* - 返回结账URL
* ------------------------------------------------- */
add_action('wp_ajax_create_direct_order', 'pc_create_direct_order');
add_action('wp_ajax_nopriv_create_direct_order', 'pc_create_direct_order');
function pc_create_direct_order() {
check_ajax_referer('woocommerce-cart', 'security');
// 初始化会话
if (!WC()->session) {
WC()->session = new WC_Session_Handler();
WC()->session->init();
}
$selected_keys = isset($_POST['selected_items']) ? (array) $_POST['selected_items'] : array();
if (empty($selected_keys)) {
wp_send_json_error(array('message' => __('请选择要结算的商品', 'woocommerce')), 400);
}
if (!WC()->cart) wc_load_cart();
// 创建完整购物车快照
$snapshot = pc_snapshot_current_cart();
// 提取选中商品
$selected = array();
foreach (WC()->cart->get_cart() as $ci_key => $ci) {
if (!in_array($ci_key, $selected_keys, true)) {
continue;
}
$pid = isset($ci['product_id']) ? (int)$ci['product_id'] : 0;
$vid = isset($ci['variation_id']) ? (int)$ci['variation_id'] : 0;
$qty = isset($ci['quantity']) ? wc_stock_amount($ci['quantity']) : 0;
$var = isset($ci['variation']) && is_array($ci['variation']) ? array_map('wc_clean', $ci['variation']) : array();
if ($pid && $qty > 0) {
$selected[] = array(
'product_id' => $pid,
'variation_id' => $vid,
'variation' => $var,
'quantity' => $qty,
);
}
}
if (empty($selected)) {
wp_send_json_error(array('message' => __('没有可结算的商品', 'woocommerce')), 400);
}
$token = wp_generate_uuid4();
$payload = array(
'uid' => pc_get_cart_uid(),
'snapshot' => $snapshot,
'selected' => $selected,
'created' => time(),
);
set_transient(pc_transient_key($token), $payload, 2 * DAY_IN_SECONDS);
// 将token存入会话
if (method_exists(WC()->session, 'set')) {
WC()->session->set('pc_partial_token', $token);
}
$checkout_url = add_query_arg('pc_token', rawurlencode($token), wc_get_checkout_url());
wp_send_json_success(array('checkout_url' => $checkout_url));
}
/* -------------------------------------------------
* 结账流程处理
* - 根据token虚拟化购物车
* - 处理前确保重新虚拟化
* - 订单标记token
* - 感谢页重建购物车
* - 返回购物车时恢复快照
* ------------------------------------------------- */
// 进入结账页时虚拟化购物车
add_action('woocommerce_before_checkout_form', 'pc_virtualize_cart_on_checkout', 1);
function pc_virtualize_cart_on_checkout() {
if (!isset($_GET['pc_token'])) return;
$token = sanitize_text_field(wp_unslash($_GET['pc_token']));
$payload = get_transient(pc_transient_key($token));
if (empty($payload) || empty($payload['selected'])) return;
if (!WC()->cart) wc_load_cart();
// 仅加载选中商品
pc_restore_cart_from_items($payload['selected']);
// 持久化token用于后续AJAX调用
if (method_exists(WC()->session, 'set')) {
WC()->session->set('pc_partial_token', $token);
}
}
// 订单处理前再次确保虚拟化
add_action('woocommerce_before_checkout_process', 'pc_revirtualize_before_processing', 1);
function pc_revirtualize_before_processing() {
if (!method_exists(WC()->session, 'get')) return;
$token = WC()->session->get('pc_partial_token');
if (!$token) return;
$payload = get_transient(pc_transient_key($token));
if (empty($payload) || empty($payload['selected'])) return;
pc_restore_cart_from_items($payload['selected']);
}
// 订单标记token
add_action('woocommerce_checkout_create_order', 'pc_tag_order_with_token', 10, 1);
function pc_tag_order_with_token($order) {
$token = null;
if (isset($_GET['pc_token'])) {
$token = sanitize_text_field(wp_unslash($_GET['pc_token']));
} elseif (method_exists(WC()->session, 'get')) {
$token = WC()->session->get('pc_partial_token');
}
if ($token) {
$order->update_meta_data('_pc_partial_token', $token);
}
}
// 感谢页重建购物车
add_action('woocommerce_thankyou', 'pc_rebuild_cart_on_thankyou', 20);
function pc_rebuild_cart_on_thankyou($order_id) {
$order = wc_get_order($order_id);
if (!$order) return;
$token = $order->get_meta('_pc_partial_token');
if (!$token) return;
$payload = get_transient(pc_transient_key($token));
if (empty($payload) || empty($payload['snapshot'])) {
// 清理会话token
if (method_exists(WC()->session, 'set')) {
WC()->session->set('pc_part极 token', null);
}
delete_transient(pc_transient_key($token));
return;
}
// 创建已购商品映射表
$purchased = array();
foreach ($order->get_items() as $item) {
$pid = (int)$item->get_product_id();
$vid = (int)$item->get_variation_id();
$qty = (int)$item->get_quantity();
$k = pc_build_item_key($pid, $vid);
if (!isset($purchased[$k])) $purchased[$极] = 0;
$purchased[$k] += $qty;
}
// 剩余商品 = 快照 - 已购
$remainder = array();
foreach ($payload['snapshot'] as $it) {
$pid = isset($it['product_id']) ? (int)$it['product_id'] : 0;
$vid = isset($it['variation_id']) ? (int)$it['variation_id'] : 0;
$qty = isset($it['quantity']) ? wc_stock_amount($it['quantity']) : 0;
$var = isset($it['variation']) ? $it['variation'] : array();
$k = pc_build_item_key($pid, $vid);
$take = isset($purchased[$k]) ? (int)$purchased[$k] : 0;
$left = max(0, $qty - $take);
if ($left > 0) {
$remainder[] = array(
'product_id' => $pid,
'variation_id' => $vid,
'variation' => $var,
'quantity' => $left,
);
$purchased[$k] = max(0, $take - $qty);
}
}
// 重建剩余商品的购物车
pc_restore_cart_from_items($remainder);
// 清理会话token
if (method_exists(WC()->session, 'set')) {
WC()->session->set('pc_partial_token', null);
}
delete_transient(pc_transient_key($token));
}
/* -------------------------------------------------
* 支付取消处理
* - 当订单
你修复到functions.php的这里而已,麻烦从这里开始,继续下去
/* -------------------------------------------------
* 支付取消处理
* - 当订单