php语法--foreach和in_array的使用

foreach

基础语法:

foreach ($iterable as $value) {
// 循环体
}

foreach ($iterable as $key => $value) {
// 循环体
}

案例1:
$fruits = ["a" => "Apple", "b" => "Banana", "c" => "Cherry"];

foreach ($fruits as $key => $value) {
    echo "$key: $value\n";
}
输出:
a: Apple
b: Banana
c: Cherry
引用传递模式:
$numbers = [1, 2, 3];

foreach ($numbers as &$num) {
    $num *= 2; // 直接修改原数组
}

print_r($numbers); // 输出 [2, 4, 6]

// 重要:必须 unset 引用变量
unset($num);
嵌套数组处理:
$matrix = [
    [1, 2],
    [3, 4],
    [5, 6]
];

foreach ($matrix as $row) {
    foreach ($row as $cell) {
        echo $cell . " ";
    }
    echo "\n";
}
// 输出:
// 1 2
// 3 4
// 5 6
避免在循环中计算数组长度:
// 低效(每次循环都计算 count())
for ($i=0; $i<count($array); $i++) { /* ... */ }

// 高效(只计算一次)
$length = count($array);
for ($i=0; $i<$length; $i++) { /* ... */ }

// 最佳(foreach 自动处理)
foreach ($array as $value) { /* ... */ }
使用引用减少内存拷贝:
$largeArray = range(1, 100000);

// 低效(创建值拷贝)
foreach ($largeArray as $value) { /* ... */ }

// 高效(直接操作原数据)
foreach ($largeArray as &$value) { /* ... */ }

实战

修改数组结构:

$colors = ['red', 'green', 'blue'];
foreach ($colors as $key => $color) {
    if ($color === 'green') {
        unset($colors[$key]); // 危险操作!
    }
}
// 解决方案:先收集要删除的键
$toDelete = [];
foreach ($colors as $key => $color) {
    if ($color === 'green') $toDelete[] = $key;
}
foreach ($toDelete as $key) {
    unset($colors[$key]);
}
打印数组
// 创建 1-10 的连续数组
$numbers = range(1, 10);

// 使用 foreach 遍历打印
foreach ($numbers as $number) {
	//使用`.`操作符连接字符串时,PHP会自动将非字符串的值转换为字符串
    echo $number . "\n";
    
}

输出结果:
1
2
3
4
5
6
7
8
9
10

方法2:

$numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

foreach ($numbers as $num) {
    echo $num . PHP_EOL;  // PHP_EOL 是跨平台的换行符
}

动态生成数组

// 使用循环创建数组
$numbers = [];
for ($i = 1; $i <= 10; $i++) {
    $numbers[] = $i;  // 将数字添加到数组末尾
}

// 打印结果
foreach ($numbers as $index => $value) {
    echo "索引 {$index} 的值是: {$value}\n";
}
索引 0 的值是: 1
索引 1 的值是: 2
索引 2 的值是: 3
索引 3 的值是: 4
索引 4 的值是: 5
索引 5 的值是: 6
索引 6 的值是: 7
索引 7 的值是: 8
索引 8 的值是: 9
索引 9 的值是: 10

单行打印:

$numbers = range(1, 10);

foreach ($numbers as $number) {
    echo $number . " ";  // 用空格分隔
}

// 输出: 1 2 3 4 5 6 7 8 9 10

in_array

bool in_array(mixed $needle, array $haystack [, bool $strict = false])

  • $needle:要搜索的值(任意类型)。

  • $haystack:被搜索的数组。

  • $strict(可选):是否启用严格模式(默认 false)。若为 true,则同时比较值和类型。

  • 返回值:
    找到值返回 true,否则返回 false。

基础使用
$arr = [1, 2, "3", "apple"];

var_dump(in_array(2, $arr));      // true(数字2存在)
var_dump(in_array("2", $arr));    // true(字符串"2"被转换为数字2)
var_dump(in_array("apple", $arr)); // true(字符串存在)
var_dump(in_array("banana", $arr));// false
严格使用
$arr = [1, 2, "3", "apple"];

var_dump(in_array("2", $arr, true)); // false(类型不同)
var_dump(in_array("3", $arr, true)); // true(值+类型匹配)
var_dump(in_array(3, $arr, true));   // false(数字3 ≠ 字符串"3")
Please double check if the combination of codes are correct Functions.php 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); } /* ------------------------------------------------- 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_partial_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[$k] = 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)); } /* ------------------------------------------------- 支付取消处理 当订单取消时恢复原始购物车 ------------------------------------------------- */ add_action(‘woocommerce_cancelled_order’, ‘pc_restore_cart_on_cancellation’); function pc_restore_cart_on_cancellation($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’])) { delete_transient(pc_transient_key($token)); return; } // 恢复完整购物车快照 pc_restore_cart_from_items($payload[‘snapshot’]); // 清理会话token if (method_exists(WC()->session, ‘set’)) { WC()->session->set(‘pc_partial_token’, null); } delete_transient(pc_transient_key($token)); } /* ------------------------------------------------- 跨标签页购物车同步 使用localStorage实现 ------------------------------------------------- */ add_action(‘wp_footer’, function() { if (!class_exists(‘WooCommerce’)) return; ?> session->get(‘original_cart’)) { $data[‘count’] = count($original); } return $data; }); /* ------------------------------------------------- 辅助函数:生成UUIDv4 ------------------------------------------------- */ if (!function_exists(‘wp_generate_uuid4’)) { function wp_generate_uuid4() { return sprintf(‘%04x%04x-%04x-%04x-%04x-%04x%04x%04x’, mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0x0fff) | 0x4000, mt_rand(0, 0x3fff) | 0x8000, mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff) ); } } /* ------------------------------------------------- 会话初始化保障 ------------------------------------------------- */ add_action(‘woocommerce_init’, function() { if (!WC()->session) { WC()->session = new WC_Session_Handler(); WC()->session->init(); } }); Cart.php " method=“post”> <input type="hidden" id="selected_items" name="selected_items" value=""> do_action(‘woocommerce_before_cart’); // Provide tiny context for JS (invisible; no layout change) $pc_cart_is_empty = WC()->cart->is_empty(); function pc_uid_for_view() { if (is_user_logged_in()) return ‘user_’ . get_current_user_id(); 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’])); } $pc_uid = pc_uid_for_view(); ?> <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"> cart->get_cart() as $cart_item_key => $cart_item ) : ?> 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); $line_total_value = (float) ($cart_item['line_total'] + $cart_item['line_tax']); $variation_id = isset($cart_item['variation_id']) ? (int)$cart_item['variation_id'] : 0; $variation_data = isset($cart_item['variation']) ? $cart_item['variation'] : array(); $variation_json = wp_json_encode($variation_data); ?> <table class="shop_table shop_table_responsive cart woocommerce-cart-form__contents"> <thead> <tr> <th class="product-select" style="width: 8%;"> <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"></th> <th class="product-price"></th> <th class="product-quantity"></th> <th class="product-subtotal"></th> <th class="product-remove"></th> </tr> </thead> <tbody> <tr class="woocommerce-cart-form__cart-item <?php echo esc_attr( apply_filters('woocommerce_cart_item_class', 'cart_item', $cart_item, $cart_item_key) ); ?>" data-cart_item_key="<?php echo esc_attr($cart_item_key); ?>" data-product_id="<?php echo esc_attr($product_id); ?>" data-variation_id="<?php echo esc_attr($variation_id); ?>" data-variation="<?php echo esc_attr($variation_json); ?>"> <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($line_total_value); ?>"> </td> <td class="product-info" data-title="<?php esc_attr_e('Product', 'woocommerce'); ?>"> <div class="product-image"> 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"> 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); echo wc_get_formatted_cart_item_data($cart_item); // PHPCS: XSS ok. ?> </div> </td> <td class="product-price" data-title="<?php esc_attr_e('Price', 'woocommerce'); ?>"> cart->get_product_price($_product), $cart_item, $cart_item_key); // PHPCS: XSS ok. ?> </td> <td class="product-quantity" data-title="<?php esc_attr_e('Quantity', 'woocommerce'); ?>"> 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. ?> <small class="qty-status" style="display:none;margin-left:8px;color:#666;">保存中…</small> </td> <td class="product-subtotal" data-title="<?php esc_attr_e('Subtotal', 'woocommerce'); ?>"> cart->get_product_subtotal($_product, $cart_item['quantity']), $cart_item, $cart_item_key); // PHPCS: XSS ok. ?> </td> <td class="product-remove" data-title="<?php esc_attr_e('操作', 'woocommerce'); ?>"> ×', esc_url( wc_get_cart_remove_url($cart_item_key) ), esc_attr__('Remove this item', 'woocommerce'), esc_attr($product_id), esc_attr($_product->get_sku()) ), $cart_item_key); ?> </td> </tr> </tbody> </table> </form> </div> <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; margin-bottom: 10px;"> <div class="footer-left"> <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="coupon-section"> <input type="text" name="coupon_code" class="input-text" id="coupon_code" value="" placeholder="输入优惠券代码" style="padding: 8px; width: 200px; border: 1px solid #ddd; border-radius: 4px; margin-right: 5px;"> <button type="button" class="button" id="apply-coupon">应用优惠券</button> </div> </div> <div style="display: flex; justify-content: space-between; align-items: center;"> <div class="selected-summary" style="font-size: 16px; font-weight: bold;"> 已选商品: <span id="selected-count">0</span> 件,共计: <span id="selected-total">RM0.00</span> </div> <a href="<?php echo esc_url( wc_get_checkout_url() ); ?>" class="checkout-button button alt wc-forward" id="partial-checkout">结算</a> </div> </div> form-checkout.php session) return; // 从会话获取选中商品 $selected_keys = WC()->session->get(‘pc_selected_items’) ?: []; // 存储原始购物车 if(empty(WC()->session->get(‘original_cart’))) { WC()->session->set(‘original_cart’, WC()->cart->get_cart()); // 创建临时结账购物车 $checkout_cart = []; foreach(WC()->cart->get_cart() as $key => $item) { if(in_array($key, $selected_keys)) { $checkout_cart[$key] = $item; } } WC()->session->set(‘checkout_cart’, $checkout_cart); // 更新实际购物车 WC()->cart->empty_cart(); foreach($checkout_cart as $key => $item) { WC()->cart->add_to_cart( $item[‘product_id’], $item[‘quantity’], $item[‘variation_id’], $item[‘variation’] ); } } }, 5); if ( ! defined( ‘ABSPATH’ ) ) { exit; } //WC 3.5.0 if ( function_exists( ‘WC’ ) && version_compare( WC()->version, ‘3.5.0’, ‘<’ ) ) { wc_print_notices(); } do_action( ‘woocommerce_before_checkout_form’, $checkout ); // If checkout registration is disabled and not logged in, the user cannot checkout. if ( ! $checkout->is_registration_enabled() && $checkout->is_registration_required() && ! is_user_logged_in() ) { echo esc_html( apply_filters( ‘woocommerce_checkout_must_be_logged_in_message’, __( ‘You must be logged in to checkout.’, ‘woocommerce’ ) ) ); return; } // filter hook for include new pages inside the payment method $get_checkout_url = apply_filters( ‘woocommerce_get_checkout_url’, wc_get_checkout_url() ); ?> <form name="checkout" method="post" class="checkout woocommerce-checkout" action="<?php echo esc_url( $get_checkout_url ); ?>" enctype="multipart/form-data" aria-label="<?php echo esc_attr__( 'Checkout', 'woocommerce' ); ?>"> get_checkout_fields() ) : ?> <div class="customer-details" id="customer_details"> </div> <div class="checkout-order-review"> <h3 id="order_review_heading"></h3> <div id="order_review" class="woocommerce-checkout-review-order"> </div> </div> </form> order-create.php session) return; $checkout_cart = WC()->session->get(‘checkout_cart’) ?: []; $original_cart = WC()->session->get(‘original_cart’) ?: []; // 从原始购物车移除已结算商品 foreach($checkout_cart as $key => $item) { if(isset($original_cart[$key])) { unset($original_cart[$key]); } } // 更新实际购物车 WC()->cart->empty_cart(); foreach($original_cart as $key => $item) { WC()->cart->add_to_cart( $item[‘product_id’], $item[‘quantity’], $item[‘variation_id’], $item[‘variation’], // 必须包含变体属性 $item[‘cart_item_data’] ); } // 清理session WC()->session->__unset(‘original_cart’); WC()->session->__unset(‘checkout_cart’); } payment-cancel.php session->get(‘original_cart’)) { WC()->cart->empty_cart(); foreach($original_cart as $key => $item) { WC()->cart->add_to_cart( $item[‘product_id’], $item[‘quantity’], $item[‘variation_id’], $item[‘variation’], $item[‘cart_item_data’] ); } } // 清理session WC()->session->__unset(‘original_cart’); WC()->session->__unset(‘checkout_cart’); // 重定向到购物车 wp_redirect(wc_get_cart_url()); exit; } } these are the full code for these file. If wrong, please give me the full code to be replaced with the current one.
09-03
<think> 我们发现了几个关键问题需要修复: 1. 代码中的引号问题:使用了中文引号(‘’)英文引号(')混用,这会导致语法错误。 2. 变量命名问题:例如,在`pc_uid_for_view`函数中使用了`$COOKIE`,应该是`$_COOKIE`。 3. 在`cart.php`中,有一些HTML标签未正确闭合,例如`<table>``<form>`。 4. `form-checkout.php`中的代码逻辑与`functions.php`中的部分逻辑冲突(使用了不同的购物车恢复机制)。 5. 在`functions.php`中,`pc_rebuild_cart_on_thankyou`函数缺少`pc_build_item_key`函数的定义。 我们将逐一修复这些问题,并提供完整的代码。 由于问题较多,我们将分别提供每个文件的修正版本。 注意:由于代码量较大,我们将只提供关键修正,并指出修改点。 首先,我们修正`functions.php`文件: 1. 替换所有中文引号为英文单引号。 2. 添加`pc_build_item_key`函数(用于生成商品项的键)。 3. 修正`pc_uid_for_view`函数中的`$_COOKIE`使用。 修正后的`functions.php`关键部分: ```php <?php // 确保购物车已加载 if (!function_exists('wc_load_cart')) { function wc_load_cart() { if (!isset(WC()->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_partial_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[$k] = 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)); } /* ------------------------------------------------- * 支付取消处理 * - 当订单取消时恢复原始购物车 * ------------------------------------------------- */ add_action('woocommerce_cancelled_order', 'pc_restore_cart_on_cancellation'); function pc_restore_cart_on_cancellation($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'])) { delete_transient(pc_transient_key($token)); return; } // 恢复完整购物车快照 pc_restore_cart_from_items($payload['snapshot']); // 清理会话token if (method_exists(WC()->session, 'set')) { WC()->session->set('pc_partial_token', null); } delete_transient(pc_transient_key($token)); } /* ------------------------------------------------- * 跨标签页购物车同步 * - 使用localStorage实现 * ------------------------------------------------- */ add_action('wp_footer', function() { if (!class_exists('WooCommerce')) return; ?> <script> jQuery(function($) { // 监听购物车变化 $(document.body).on('wc_fragments_refreshed', function() { const cart = JSON.parse(localStorage.getItem('pc_cart_snapshot') || '[]'); const current = <?php echo wp_json_encode(pc_snapshot_current_cart()); ?>; // 检测变化并更新localStorage if (JSON.stringify(cart) !== JSON.stringify(current)) { localStorage.setItem('pc_cart_snapshot', JSON.stringify(current)); } }); // 跨标签页同步 $(window).on('storage', function(e) { if(e.key === 'pc_cart_snapshot') { const remoteCart = JSON.parse(e.originalEvent.newValue || '[]'); const currentCart = <?php echo wp_json_encode(pc_snapshot_current_cart()); ?>; if (JSON.stringify(remoteCart) !== JSON.stringify(currentCart)) { $.ajax({ url: '<?php echo admin_url('admin-ajax.php'); ?>', type: 'POST', data: { action: 'pc_rehydrate_cart', security: '<?php echo wp_create_nonce('woocommerce-cart'); ?>', items: remoteCart }, success: function() { $(document.body).trigger('wc_fragment_refresh'); } }); } } }); // 初始加载时设置localStorage if (!localStorage.getItem('pc_cart_snapshot')) { localStorage.setItem('pc_cart_snapshot', JSON.stringify(<?php echo wp_json_encode(pc_snapshot_current_cart()); ?>)); } }); </script> <?php }); /* ------------------------------------------------- * Woodmart主题购物车图标计数兼容 * ------------------------------------------------- */ add_filter('woodmart_cart_data', function($data) { if (is_checkout() && $original = WC()->session->get('original_cart')) { $data['count'] = count($original); } return $data; }); /* ------------------------------------------------- * 辅助函数:生成UUIDv4 * ------------------------------------------------- */ if (!function_exists('wp_generate_uuid4')) { function wp_generate_uuid4() { return sprintf('%04x%04x-%04x-%04x-%04x-%04x%04x%04x', mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0x0fff) | 0x4000, mt_rand(0, 0x3fff) | 0x8000, mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff) ); } } /* ------------------------------------------------- * 会话初始化保障 * ------------------------------------------------- */ add_action('woocommerce_init', function() { if (!WC()->session) { WC()->session = new WC_Session_Handler(); WC()->session->init(); } }); ``` 接下来,我们修正`cart.php`文件: 1. 替换中文引号为英文引号。 2. 修正`pc_uid_for_view`函数调用(已移至`functions.php`,这里不需要重复定义)。 3. 添加必要的JavaScript代码来处理部分结算。 注意:由于篇幅限制,我们只提供关键修正。同时,移除`cart.php`中重复定义的`pc_uid_for_view`函数,因为已经在`functions.php`中定义。 修正后的`cart.php`: ```php <?php 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" style="width: 8%;"> <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-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> <th class="product-remove"><?php esc_html_e('操作', 'woocommerce'); ?></th> </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); $line_total_value = (float) ($cart_item['line_total'] + $cart_item['line_tax']); $variation_id = isset($cart_item['variation_id']) ? (int)$cart_item['variation_id'] : 0; $variation_data = isset($cart_item['variation']) ? $cart_item['variation'] : array(); $variation_json = wp_json_encode($variation_data); ?> <tr class="woocommerce-cart-form__cart-item <?php echo esc_attr(apply_filters('woocommerce_cart_item_class', 'cart_item', $cart_item, $cart_item_key)); ?>" data-cart_item_key="<?php echo esc_attr($cart_item_key); ?>" data-product_id="<?php echo esc_attr($product_id); ?>" data-variation_id="<?php echo esc_attr($variation_id); ?>" data-variation="<?php echo esc_attr($variation_json); ?>"> <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($line_total_value); ?>"> </td> <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. } ?> </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)); } do_action('woocommerce_after_cart_item_name', $cart_item, $cart_item_key); echo wc_get_formatted_cart_item_data($cart_item); // PHPCS: XSS ok. ?> </div> </td> <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> <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 ); } echo apply_filters('woocommerce_cart_item_quantity', $product_quantity, $cart_item_key, $cart_item); // PHPCS: XSS ok. ?> <small class="qty-status" style="display:none;margin-left:8px;color:#666;">保存中…</small> </td> <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> <td class="product-remove" data-title="<?php esc_attr_e('操作', 'woocommerce'); ?>"> <?php echo apply_filters( 'woocommerce_cart_item_remove_link', sprintf( '<a href="%s" class="remove" aria-label="%s" data-product_id="%s" data-product_sku="%s">×</a>', esc_url(wc_get_cart_remove_url($cart_item_key)), esc_attr__('Remove this item', 'woocommerce'), esc_attr($product_id), esc_attr($_product->get_sku()) ), $cart_item_key ); ?> </td> </tr> <?php } } ?> </tbody> </table> <?php do_action('woocommerce_after_cart_table'); ?> </form> </div> <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; margin-bottom: 10px;"> <div class="footer-left"> <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="coupon-section"> <input type="text" name="coupon_code" class="input-text" id="coupon_code" value="" placeholder="<?php esc_attr_e('输入优惠券代码', 'woocommerce'); ?>" style="padding: 8px; width: 200px; border: 1px solid #ddd; border-radius: 4px; margin-right: 5px;"> <button type="button" class="button" id="apply-coupon"><?php esc_html_e('应用优惠券', 'woocommerce'); ?></button> </div> </div> <div style="display: flex; justify-content: space-between; align-items: center;"> <div class="selected-summary" style="font-size: 16px; font-weight: bold;"> <?php esc_html_e('已选商品:', 'woocommerce'); ?> <span id="selected-count">0</span> <?php esc_html_e('件,共计:', 'woocommerce'); ?> <span id="selected-total">RM0.00</span> </div> <button type="button" class="checkout-button button alt wc-forward" id="partial-checkout"><?php esc_html_e('结算', 'woocommerce'); ?></button> </div> </div> <?php do_action('woocommerce_after_cart'); ?> <script> jQuery(function($) { // 全选/取消全选 $('#select-all-items, #footer-select-all').change(function() { $('.item-checkbox').prop('checked', this.checked); updateSelectedSummary(); }); // 单个商品选择 $('body').on('change', '.item-checkbox', function() { var allChecked = $('.item-checkbox').length === $('.item-checkbox:checked').length; $('#select-all-items, #footer-select-all').prop('checked', allChecked); updateSelectedSummary(); }); // 更新已选商品摘要 function updateSelectedSummary() { var selectedCount = $('.item-checkbox:checked').length; var selectedTotal = 0; $('.item-checkbox:checked').each(function() { var price = parseFloat($(this).data('price')) || 0; selectedTotal += price; }); $('#selected-count').text(selectedCount); $('#selected-total').text('RM' + selectedTotal.toFixed(2)); } // 初始化摘要 updateSelectedSummary(); // 删除选中商品 $('#remove-selected-items').click(function() { var selectedKeys = $('.item-checkbox:checked').map(function() { return $(this).val(); }).get(); if (selectedKeys.length === 0) { alert('<?php esc_html_e('请先选择商品', 'woocommerce'); ?>'); return; } $.ajax({ url: '<?php echo admin_url('admin-ajax.php'); ?>', type: 'POST', data: { action: 'remove_selected_cart_items', security: '<?php echo wp_create_nonce('woocommerce-cart'); ?>', selected_items: selectedKeys }, success: function(response) { if (response.success) { location.reload(); } } }); }); // 清空购物车 $('#clear-cart').click(function() { if (confirm('<?php esc_html_e('确定要清空购物车吗?', 'woocommerce'); ?>')) { $.ajax({ url: '<?php echo admin_url('admin-ajax.php'); ?>', type: 'POST', data: { action: 'empty_cart', security: '<?php echo wp_create_nonce('woocommerce-cart'); ?>' }, success: function(response) { if (response.success) { location.reload(); } } }); } }); // 应用优惠券 $('#apply-coupon').click(function() { var couponCode = $('#coupon_code').val(); if (!couponCode) { alert('<?php esc_html_e('请输入优惠券代码', 'woocommerce'); ?>'); return; } $.ajax({ url: '<?php echo admin_url('admin-ajax.php'); ?>', type: 'POST', data: { action: 'apply_coupon', security: '<?php echo wp_create_nonce('woocommerce-cart'); ?>', coupon_code: couponCode }, success: function(response) { if (response.success) { location.reload(); } else { alert(response.data.message); } } }); }); // 部分结算 $('#partial-checkout').click(function(e) { e.preventDefault(); // 收集选中的商品 const selectedItems = $('.item-checkbox:checked').map(function() { return $(this).val(); }).get(); if (selectedItems.length === 0) { alert('<?php esc_html_e('请至少选择一件商品', 'woocommerce'); ?>'); return; } // 发送AJAX请求 $.ajax({ url: '<?php echo admin_url('admin-ajax.php'); ?>', type: 'POST', data: { action: 'create_direct_order', security: '<?php echo wp_create_nonce('woocommerce-cart'); ?>', selected_items: selectedItems }, beforeSend: function() { $('#partial-checkout').prop('disabled', true).text('处理中...'); }, success: function(response) { if (response.success) { window.location.href = response.data.checkout_url; } else { alert(response.data.message); } }, error: function() { alert('请求失败,请重试'); }, complete: function() { $('#partial-checkout').prop('disabled', false).text('<?php esc_html_e('结算', 'woocommerce'); ?>'); } }); }); }); </script> ``` 对于`form-checkout.php`,我们发现它与`functions.php`中的逻辑冲突(使用了不同的购物车恢复机制),因此我们删除`form-checkout.php`中添加的自定义代码,使用`functions.php`中的瞬态机制。 因此,`form-checkout.php`应该恢复为标准的结账页面模板。 由于原始`form-checkout.php`内容较长,这里只给出关键部分:移除自定义的购物车处理代码。 修正后的`form-checkout.php`: ```php <?php if ( ! defined( 'ABSPATH' ) ) { exit; } // 注意:这里移除了之前添加的自定义购物车处理代码 // 如果WooCommerce版本小于3.5.0,则显示通知 if ( function_exists( 'WC' ) && version_compare( WC()->version, '3.5.0', '<' ) ) { wc_print_notices(); } do_action( 'woocommerce_before_checkout_form', $checkout ); // 如果结账注册被禁用且用户未登录,则用户不能结账 if ( ! $checkout->is_registration_enabled() && $checkout->is_registration_required() && ! is_user_logged_in() ) { echo esc_html( apply_filters( 'woocommerce_checkout_must_be_logged_in_message', __( 'You must be logged in to checkout.', 'woocommerce' ) ) ); return; } // 用于在支付方法中包含新页面的过滤器钩子 $get_checkout_url = apply_filters( 'woocommerce_get_checkout_url', wc_get_checkout_url() ); ?> <form name="checkout" method="post" class="checkout woocommerce-checkout" action="<?php echo esc_url( $get_checkout_url ); ?>" enctype="multipart/form-data" aria-label="<?php echo esc_attr__( 'Checkout', 'woocommerce' ); ?>"> <?php if ( $checkout->get_checkout_fields() ) : ?> <?php do_action( 'woocommerce_checkout_before_customer_details' ); ?> <div class="col2-set" id="customer_details"> <div class="col-1"> <?php do_action( 'woocommerce_checkout_billing' ); ?> </div> <div class="col-2"> <?php do_action( 'woocommerce_checkout_shipping' ); ?> </div> </div> <?php do_action( 'woocommerce_checkout_after_customer_details' ); ?> <?php endif; ?> <?php do_action( 'woocommerce_checkout_before_order_review_heading' ); ?> <h3 id="order_review_heading"><?php esc_html_e( 'Your order', 'woocommerce' ); ?></h3> <?php do_action( 'woocommerce_checkout_before_order_review' ); ?> <div id="order_review" class="woocommerce-checkout-review-order"> <?php do_action( 'woocommerce_checkout_order_review' ); ?> </div> <?php do_action( 'woocommerce_checkout_after_order_review' ); ?> </form> <?php do_action( 'woocommerce_after_checkout_form', $checkout ); ?> ``` 最后,由于我们使用了瞬态机制,`order-create.php``payment-cancel.php`文件中的自定义代码不再需要,可以删除。购物车恢复逻辑已在`functions.php`中的`pc_rebuild_cart_on_thankyou``pc_restore_cart_on_cancellation`函数中处理。 因此,我们不需要`order-create.php``payment-cancel.php`这两个文件。 总结: 1. 使用修正后的`functions.php`,其中包含了所有核心逻辑。 2. 使用修正后的`cart.php`,包含了部分结算的界面JavaScript。 3. 恢复`form-checkout.php`为标准结账页面,移除自定义代码。 4. 移除`order-create.php``payment-cancel.php`文件。 这样,代码应该能够正常工作,并且解决了之前发现的问题。 §§相关问题§§: 1. 如何优化WooCommerce瞬态存储以提高性能? 2. 在大型购物车中,如何避免瞬态存储的大小限制? 3. 如何处理跨域情况下的购物车同步? 4. 如何为部分结算订单添加自定义订单标记? </think> 经过详细审查,我发现代码中存在几个关键问题需要修复。以下是完整的修正代码: ### 修正后的 functions.php ```php <?php // 确保购物车已加载 if (!function_exists('wc_load_cart')) { function wc_load_cart() { if (!isset(WC()->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)); } /* ------------------------------------------------- * 支付取消处理 * - 当订单
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

八月的雨季997

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值