WordPress 自定义 WP_Query 循环如何支持 tax_query or meta_query 参数

WP_Query OR 查询技巧

WordPress 的循环函数都是 and 方式链接,对于单个的 meta_query 或者 tax_query 字段内部才能使用 or,那么如果我们想要实现 tax_query or meta_query 的关系,WordPress 默认是不提供支持的。泪雪网 https://www.leixue.com

WordPress WP_Query 自定义

子凡最近为了满足泪雪网的功能需求,查找了大量的教程,甚至想过用两个 WP_Query 循环来实现这样的功能,后来通过 Google 搜索到一个相关的答案,为此子凡整理并分享出来,这样当你在使用 WordPress 的 WP_Query 来自定义循环,并且完美的支持 tax_query or meta_query。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/**
 * Modify WP_Query to support 'meta_or_tax' argument
 * to use OR between meta- and taxonomy query parts.
 * use '_meta_or_tax' => true in wp_query array
 */
add_filter( 'posts_where', function( $where, \WP_Query $q ){
	$tax_args = isset( $q->query_vars['tax_query'] ) ? $q->query_vars['tax_query'] : null;
	$meta_args = isset( $q->query_vars['meta_query'] ) ? $q->query_vars['meta_query'] : null;
	$meta_or_tax = isset( $q->query_vars['_meta_or_tax'] ) ? wp_validate_boolean( $q->query_vars['_meta_or_tax'] ) : false;
	// Construct the "tax OR meta" query
	if( $meta_or_tax && is_array( $tax_args ) &&  is_array( $meta_args )  )   {
		global $wpdb;
		$field = 'ID';// Primary id column
		$sql_tax = get_tax_sql(  $tax_args,  $wpdb->posts, $field );// Tax query
		$sql_meta = get_meta_sql( $meta_args, 'post', $wpdb->posts, $field );// Meta query
		// Modify the 'where' part
		if( isset( $sql_meta['where'] ) && isset( $sql_tax['where'] ) ) {
			$where = str_replace( [ $sql_meta['where'], $sql_tax['where'] ], '', $where );
			$where .= sprintf( ' AND ( %s OR  %s ) ', substr( trim( $sql_meta['where'] ), 4 ), substr( trim( $sql_tax['where']  ), 4 ) );
		}
	}
	return $where;
}, PHP_INT_MAX, 2 );

使用方式则是在 WP_Query 的参数数组里面添加一条'_meta_or_tax' => true,简单的举个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
$args = array(
	'post_status'			=> 'publish',
	'order'					=> 'ASC',
	'nopaging'				=> true,
	'_meta_or_tax'			=> true, //用于支持 tax_query OR meta_query 查询
	'tax_query'				=> array(
		'relation'		=> 'OR',
		array(
			'taxonomy'	=> 'category',
			'field'		=> 'id',
			'terms'		=> array(1,2,3),
			'operator'	=> 'IN'
		), 
	),
	'meta_query'			=> array(
		array(
			'key'		=> 'Headline',
			'value'		=> ''
			'compare'	=> '!='
		),
	)
);
$query = new WP_Query( $args );

这可能是一个非常小众的需求,但是用起来还是非常的爽,而且对于有相关功能需求的来说,以及用两次循环甚至三次循环来搞定简直不要不要的,子凡我要的就是最极简最极致的功能,也要最简单高效的代码。

更多关于 WordPress 优化及疑问可以添加 QQ 群:255308000

除非注明,否则均为泪雪网原创文章,禁止任何形式转载

本文链接:https://zhangzifan.com/wordpress-wp_query-tax_query-or-meta_query.html

if (!function_exists('get_article_for_category')) { function get_article_for_category( $category, $posts_per_page = 5, $tag = '' ,// 新增参数:标签(tag) $include_meta = true, $include_acf = true, $orderby = 'menu_order', $order = 'DESC' ) { // 限制只允许的排序字段 $allowed_orderby = array('date', 'menu_order'); if (!in_array($orderby, $allowed_orderby)) { $orderby = 'date'; // 默认回退到按时间排序 } // 设置基础查询参数 $args = array( 'posts_per_page' => $posts_per_page, 'orderby' => $orderby, 'order' => $order, ); // 添加分类查询条件 if (is_numeric($category)) { $args['tax_query'][] = array( 'taxonomy' => 'category', 'field' => 'term_id', 'terms' => $category, ); } else { $args['tax_query'][] = array( 'taxonomy' => 'category', 'field' => 'slug', 'terms' => $category, ); } if (!empty($tag)) { $args['tax_query']['relation'] = 'AND'; if (is_numeric($tag)) { $args['tax_query'][] = array( 'taxonomy' => 'post_tag', 'field' => 'term_id', 'terms' => $tag, ); } else { $args['tax_query'][] = array( 'taxonomy' => 'post_tag', 'field' => 'slug', 'terms' => $tag, ); } } if ($orderby === 'menu_order') { $args['orderby'] = 'menu_order'; } $query = new WP_Query($args); if ($query->have_posts()) { $posts = array(); while ($query->have_posts()) { $query->the_post(); $post_id = get_the_ID(); $post_data = array( 'id' => $post_id, 'title' => get_the_title(), 'permalink' => get_the_permalink(), 'excerpt' => get_the_excerpt(), 'content' => get_the_content(), 'thumbnail' => has_post_thumbnail() ? get_the_post_thumbnail_url() : '', 'date' => get_the_date(), 'author' => get_the_author(), 'modified_date' => get_the_modified_date(), 'type' => get_post_type(), 'status' => get_post_status(), 'comment_count' => get_comments_number(), ); // 获取所有自定义字段(post meta) if ($include_meta) { $meta = get_post_meta($post_id); $post_data['meta'] = $meta; } // 如果使用了 ACF,获取 ACF 字段 if ($include_acf && function_exists('get_fields')) { $acf_fields = get_fields(); if ($acf_fields) { $post_data['acf'] = $acf_fields; } } $posts[] = $post_data; } wp_reset_postdata(); return $posts; } return false; } }
07-22
cart.php <?php defined('ABSPATH') || exit; /** * 健壮的部分结算系统 - 带持久化购物车快照 * - 结算前创建完整购物车快照 * - 订单创建成功后才移除商品 * - 感谢页面重建购物车(快照 - 已购买商品) * - 取消/返回时恢复完整快照 * - 访客支持:localStorage + AJAX 重新水合 */ /* ------------------------------------------------- * 辅助函数 * ------------------------------------------------- */ /** * 购物车数量AJAX端点 */ add_action('wp_ajax_get_cart_count', 'pc_get_cart_count'); add_action('wp_ajax_nopriv_get_cart_count', 'pc_get_cart_count'); function pc_get_cart_count() { check_ajax_referer('woocommerce-cart', 'security'); $count = WC()->cart->get_cart_contents_count(); wp_send_json_success(array('count' => $count)); } function pc_get_cart_uid() { 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'])); } function pc_build_item_key($product_id, $variation_id = 0) { return (int)$product_id . '|' . (int)$variation_id; } function pc_snapshot_current_cart() { if (!isset(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' => $items, 'coupons' => WC()->cart->get_applied_coupons() ]; } /** * 恢复购物车优惠券 */ function pc_restore_cart_coupons($coupons) { if (!isset(WC()->cart)) { wc_load_cart(); } // 先移除所有现有优惠券 foreach (WC()->cart->get_applied_coupons() as $coupon_code) { WC()->cart->remove_coupon($coupon_code); } // 应用快照中的优惠券 foreach ($coupons as $coupon_code) { if (WC()->cart->is_valid_coupon($coupon_code)) { WC()->cart->apply_coupon($coupon_code); } } WC()->cart->calculate_totals(); } function pc_restore_cart_from_items($items) { if (!isset(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) { $product = wc_get_product($pid); // 检查商品是否有效且库存可用 if ($product && $product->exists() && $product->is_in_stock()) { // 获取库存数量 $stock_qty = $product->get_stock_quantity(); if ($stock_qty !== null) { $actual_qty = min($qty, $stock_qty); } else { $actual_qty = $qty; } WC()->cart->add_to_cart( $pid, $actual_qty, $vid, $var ); } } } WC()->cart->calculate_totals(); } // 完全重构的购物车恢复逻辑 - 确保WC会话存在 add_action('wp_loaded', function() { // 严格检查WC会话可用性 $wc = function_exists('WC') ? WC() : null; if (!$wc) return; $session = property_exists($wc, 'session') ? $wc->session : null; if (!$session) return; $token = method_exists($session, 'get') ? $session->get('pc_partial_token') : null; if (!$token) return; // 检查购物车是否为空 $cart = property_exists($wc, 'cart') ? $wc->cart : null; if (!$cart) return; if ($cart->is_empty()) { $payload = get_transient(pc_transient_key($token)); if (!empty($payload['snapshot'])) { pc_restore_cart_from_items($payload['snapshot']['items']); pc_restore_cart_coupons($payload['snapshot']['coupons']); $cart->calculate_totals(); } } }, 20); function pc_transient_key($token) { return 'pc_partial_payload_' . sanitize_key($token); } /* ------------------------------------------------- * AJAX: 当Woo购物车为空时本地重新水合 * ------------------------------------------------- */ 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 (!isset(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) { $product = wc_get_product($pid); if ($product && $product->exists() && $product->is_in_stock()) { // 检查库存 $stock_qty = $product->get_stock_quantity(); if ($stock_qty !== null) { $qty = min($qty, $stock_qty); } 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 (!isset(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']); // 应用动态折扣 $discounted_total = apply_filters('pc_dynamic_discount', $line_total_incl_tax, $cart_item); wp_send_json_success(array( 'subtotal_html' => $subtotal_html, 'line_total_incl_tax' => $line_total_incl_tax, 'discounted_total' => $discounted_total, // 添加折扣后的价格 '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 (!isset(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 (!isset(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 (!isset(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: 启动部分结算到常规结算页面 * ------------------------------------------------- */ 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'); $selected_keys = isset($_POST['selected_items']) ? (array) $_POST['selected_items'] : array(); if (empty($selected_keys)) { wp_send_json_error(array('message' => __('请选择要结算的商品', 'woocommerce')), 400); } if (!isset(WC()->cart)) { wc_load_cart(); } // 创建完整购物车快照 // 修正函数名:pc_snapshot_current_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 = (int)$ci['product_id']; $vid = (int)$ci['variation_id']; $qty = wc_stock_amount($ci['quantity']); $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, // 现在包含 items + coupons 'selected' => $selected, 'created' => time(), ); set_transient(pc_transient_key($token), $payload, 2 * DAY_IN_SECONDS); // 将会话令牌存入WooCommerce会话 if (isset(WC()->session) && 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)); } /* ------------------------------------------------- * 结账时虚拟化购物车并在购买后重建 * ------------------------------------------------- */ // 结账时只恢复选中的商品 add_action('woocommerce_before_checkout_form', function() { 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; // 严格检查WC会话可用性 if (!function_exists('WC') || !is_callable('WC')) return; $wc = WC(); if (!$wc || !property_exists($wc, 'session')) return; // 只恢复选中的商品 pc_restore_cart_from_items($payload['selected']); // 设置会话令牌 if (method_exists($wc->session, 'set')) { $wc->session->set('pc_partial_token', $token); } }, 1); // 订单处理前确保虚拟化 add_action('woocommerce_before_checkout_process', function() { if (!isset(WC()->session) || !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']); }, 1); // 为订单添加令牌标记 add_action('woocommerce_checkout_create_order', function($order) { $token = null; if (isset($_GET['pc_token'])) { $token = sanitize_text_field(wp_unslash($_GET['pc_token'])); } elseif (isset(WC()->session) && method_exists(WC()->session, 'get')) { $token = WC()->session->get('pc_partial_token'); } if ($token) { $order->update_meta_data('_pc_partial_token', $token); $order->update_meta_data('_pc_cart_snapshot', $token); } }, 10, 1); // 成功结账后仅移除已购买商品 add_action('woocommerce_thankyou', function($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'])) { if (isset(WC()->session) && method_exists(WC()->session, 'set')) { WC()->session->set('pc_partial_token', null); } delete_transient(pc_transient_key($token)); return; } // 1. 恢复完整快照 pc_restore_cart_from_items($payload['snapshot']['items']); pc_restore_cart_coupons($payload['snapshot']['coupons']); WC()->cart->calculate_totals(); // 2. 只移除已购买商品 $removed_count = 0; foreach ($payload['selected'] as $selected_item) { $cart_item_key = pc_find_cart_item($selected_item['product_id'], $selected_item['variation_id']); if ($cart_item_key) { WC()->cart->remove_cart_item($cart_item_key); $removed_count++; } } // 3. 如果有商品被移除才重新计算 if ($removed_count > 0) { WC()->cart->calculate_totals(); } // 清理令牌 if (isset(WC()->session) && method_exists(WC()->session, 'set')) { WC()->session->set('pc_partial_token', null); } delete_transient(pc_transient_key($token)); }, 20); // 辅助函数:通过产品和变体ID查找购物车项 function pc_find_cart_item($product_id, $variation_id = 0) { if (!isset(WC()->cart)) { wc_load_cart(); } foreach (WC()->cart->get_cart() as $cart_item_key => $cart_item) { $cart_pid = isset($cart_item['product_id']) ? (int)$cart_item['product_id'] : 0; $cart_vid = isset($cart_item['variation_id']) ? (int)$cart_item['variation_id'] : 0; if ($cart_pid == $product_id && $cart_vid == $variation_id) { return $cart_item_key; } } return false; } // 访问购物车页面时恢复完整快照(返回/取消操作) add_action('woocommerce_before_cart', function() { // 严格检查会话可用性 if (!isset(WC()->session) || !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['snapshot'])) return; // 恢复完整快照 pc_restore_cart_from_items($payload['snapshot']['items']); pc_restore_cart_coupons($payload['snapshot']['coupons']); WC()->cart->calculate_totals(); }); /* ------------------------------------------------- * 保持购物车数量在结算过程中准确 * ------------------------------------------------- */ add_filter('woocommerce_cart_contents_count', function($count) { // 检查是否存在部分结算令牌 if (!isset(WC()->session) || !method_exists(WC()->session, 'get')) return $count; $token = WC()->session->get('pc_partial_token'); if (!$token) return $count; $payload = get_transient(pc_transient_key($token)); // 始终显示完整购物车数量 if (!empty($payload['snapshot']) && is_array($payload['snapshot']['items'])) { $snapshot_count = 0; foreach ($payload['snapshot']['items'] as $item) { $snapshot_count += (int)($item['quantity'] ?? 0); } return $snapshot_count; } return $count; }); // 确保购物车一致性 add_action('woocommerce_before_cart', 'pc_maintain_cart_consistency'); add_action('woocommerce_before_checkout_form', 'pc_maintain_cart_consistency'); function pc_maintain_cart_consistency() { if (!isset(WC()->session) || !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['snapshot'])) return; // 立即恢复完整购物车以确保UI一致性 pc_restore_cart_from_items($payload['snapshot']['items']); pc_restore_cart_coupons($payload['snapshot']['coupons']); WC()->cart->calculate_totals(); } // 在 functions.php 中添加折扣过滤器 add_filter('pc_dynamic_discount', function($price, $cart_item) { // 这里是您的动态折扣计算逻辑 // 示例:应用10%折扣 return $price * 0.9; }, 10, 2); functions.php <?php defined('ABSPATH') || exit; /** * 健壮的部分结算系统 - 带持久化购物车快照 * - 结算前创建完整购物车快照 * - 订单创建成功后才移除商品 * - 感谢页面重建购物车(快照 - 已购买商品) * - 取消/返回时恢复完整快照 * - 访客支持:localStorage + AJAX 重新水合 */ /* ------------------------------------------------- * 辅助函数 * ------------------------------------------------- */ /** * 购物车数量AJAX端点 */ add_action('wp_ajax_get_cart_count', 'pc_get_cart_count'); add_action('wp_ajax_nopriv_get_cart_count', 'pc_get_cart_count'); function pc_get_cart_count() { check_ajax_referer('woocommerce-cart', 'security'); $count = WC()->cart->get_cart_contents_count(); wp_send_json_success(array('count' => $count)); } function pc_get_cart_uid() { 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'])); } function pc_build_item_key($product_id, $variation_id = 0) { return (int)$product_id . '|' . (int)$variation_id; } function pc_snapshot_current_cart() { if (!isset(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' => $items, 'coupons' => WC()->cart->get_applied_coupons() ]; } /** * 恢复购物车优惠券 */ function pc_restore_cart_coupons($coupons) { if (!isset(WC()->cart)) { wc_load_cart(); } // 先移除所有现有优惠券 foreach (WC()->cart->get_applied_coupons() as $coupon_code) { WC()->cart->remove_coupon($coupon_code); } // 应用快照中的优惠券 foreach ($coupons as $coupon_code) { if (WC()->cart->is_valid_coupon($coupon_code)) { WC()->cart->apply_coupon($coupon_code); } } WC()->cart->calculate_totals(); } function pc_restore_cart_from_items($items) { if (!isset(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) { $product = wc_get_product($pid); // 检查商品是否有效且库存可用 if ($product && $product->exists() && $product->is_in_stock()) { // 获取库存数量 $stock_qty = $product->get_stock_quantity(); if ($stock_qty !== null) { $actual_qty = min($qty, $stock_qty); } else { $actual_qty = $qty; } WC()->cart->add_to_cart( $pid, $actual_qty, $vid, $var ); } } } WC()->cart->calculate_totals(); } // 完全重构的购物车恢复逻辑 - 确保WC会话存在 add_action('wp_loaded', function() { // 严格检查WC会话可用性 $wc = function_exists('WC') ? WC() : null; if (!$wc) return; $session = property_exists($wc, 'session') ? $wc->session : null; if (!$session) return; $token = method_exists($session, 'get') ? $session->get('pc_partial_token') : null; if (!$token) return; // 检查购物车是否为空 $cart = property_exists($wc, 'cart') ? $wc->cart : null; if (!$cart) return; if ($cart->is_empty()) { $payload = get_transient(pc_transient_key($token)); if (!empty($payload['snapshot'])) { pc_restore_cart_from_items($payload['snapshot']['items']); pc_restore_cart_coupons($payload['snapshot']['coupons']); $cart->calculate_totals(); } } }, 20); function pc_transient_key($token) { return 'pc_partial_payload_' . sanitize_key($token); } /* ------------------------------------------------- * AJAX: 当Woo购物车为空时本地重新水合 * ------------------------------------------------- */ 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 (!isset(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) { $product = wc_get_product($pid); if ($product && $product->exists() && $product->is_in_stock()) { // 检查库存 $stock_qty = $product->get_stock_quantity(); if ($stock_qty !== null) { $qty = min($qty, $stock_qty); } 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 (!isset(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']); // 应用动态折扣 $discounted_total = apply_filters('pc_dynamic_discount', $line_total_incl_tax, $cart_item); wp_send_json_success(array( 'subtotal_html' => $subtotal_html, 'line_total_incl_tax' => $line_total_incl_tax, 'discounted_total' => $discounted_total, // 添加折扣后的价格 '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 (!isset(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 (!isset(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 (!isset(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: 启动部分结算到常规结算页面 * ------------------------------------------------- */ 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'); $selected_keys = isset($_POST['selected_items']) ? (array) $_POST['selected_items'] : array(); if (empty($selected_keys)) { wp_send_json_error(array('message' => __('请选择要结算的商品', 'woocommerce')), 400); } if (!isset(WC()->cart)) { wc_load_cart(); } // 创建完整购物车快照 // 修正函数名:pc_snapshot_current_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 = (int)$ci['product_id']; $vid = (int)$ci['variation_id']; $qty = wc_stock_amount($ci['quantity']); $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, // 现在包含 items + coupons 'selected' => $selected, 'created' => time(), ); set_transient(pc_transient_key($token), $payload, 2 * DAY_IN_SECONDS); // 将会话令牌存入WooCommerce会话 if (isset(WC()->session) && 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)); } /* ------------------------------------------------- * 结账时虚拟化购物车并在购买后重建 * ------------------------------------------------- */ // 结账时只恢复选中的商品 add_action('woocommerce_before_checkout_form', function() { 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; // 严格检查WC会话可用性 if (!function_exists('WC') || !is_callable('WC')) return; $wc = WC(); if (!$wc || !property_exists($wc, 'session')) return; // 只恢复选中的商品 pc_restore_cart_from_items($payload['selected']); // 设置会话令牌 if (method_exists($wc->session, 'set')) { $wc->session->set('pc_partial_token', $token); } }, 1); // 订单处理前确保虚拟化 add_action('woocommerce_before_checkout_process', function() { if (!isset(WC()->session) || !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']); }, 1); // 为订单添加令牌标记 add_action('woocommerce_checkout_create_order', function($order) { $token = null; if (isset($_GET['pc_token'])) { $token = sanitize_text_field(wp_unslash($_GET['pc_token'])); } elseif (isset(WC()->session) && method_exists(WC()->session, 'get')) { $token = WC()->session->get('pc_partial_token'); } if ($token) { $order->update_meta_data('_pc_partial_token', $token); $order->update_meta_data('_pc_cart_snapshot', $token); } }, 10, 1); // 成功结账后仅移除已购买商品 add_action('woocommerce_thankyou', function($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'])) { if (isset(WC()->session) && method_exists(WC()->session, 'set')) { WC()->session->set('pc_partial_token', null); } delete_transient(pc_transient_key($token)); return; } // 1. 恢复完整快照 pc_restore_cart_from_items($payload['snapshot']['items']); pc_restore_cart_coupons($payload['snapshot']['coupons']); WC()->cart->calculate_totals(); // 2. 只移除已购买商品 $removed_count = 0; foreach ($payload['selected'] as $selected_item) { $cart_item_key = pc_find_cart_item($selected_item['product_id'], $selected_item['variation_id']); if ($cart_item_key) { WC()->cart->remove_cart_item($cart_item_key); $removed_count++; } } // 3. 如果有商品被移除才重新计算 if ($removed_count > 0) { WC()->cart->calculate_totals(); } // 清理令牌 if (isset(WC()->session) && method_exists(WC()->session, 'set')) { WC()->session->set('pc_partial_token', null); } delete_transient(pc_transient_key($token)); }, 20); // 辅助函数:通过产品和变体ID查找购物车项 function pc_find_cart_item($product_id, $variation_id = 0) { if (!isset(WC()->cart)) { wc_load_cart(); } foreach (WC()->cart->get_cart() as $cart_item_key => $cart_item) { $cart_pid = isset($cart_item['product_id']) ? (int)$cart_item['product_id'] : 0; $cart_vid = isset($cart_item['variation_id']) ? (int)$cart_item['variation_id'] : 0; if ($cart_pid == $product_id && $cart_vid == $variation_id) { return $cart_item_key; } } return false; } // 访问购物车页面时恢复完整快照(返回/取消操作) add_action('woocommerce_before_cart', function() { // 严格检查会话可用性 if (!isset(WC()->session) || !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['snapshot'])) return; // 恢复完整快照 pc_restore_cart_from_items($payload['snapshot']['items']); pc_restore_cart_coupons($payload['snapshot']['coupons']); WC()->cart->calculate_totals(); }); /* ------------------------------------------------- * 保持购物车数量在结算过程中准确 * ------------------------------------------------- */ add_filter('woocommerce_cart_contents_count', function($count) { // 检查是否存在部分结算令牌 if (!isset(WC()->session) || !method_exists(WC()->session, 'get')) return $count; $token = WC()->session->get('pc_partial_token'); if (!$token) return $count; $payload = get_transient(pc_transient_key($token)); // 始终显示完整购物车数量 if (!empty($payload['snapshot']) && is_array($payload['snapshot']['items'])) { $snapshot_count = 0; foreach ($payload['snapshot']['items'] as $item) { $snapshot_count += (int)($item['quantity'] ?? 0); } return $snapshot_count; } return $count; }); // 确保购物车一致性 add_action('woocommerce_before_cart', 'pc_maintain_cart_consistency'); add_action('woocommerce_before_checkout_form', 'pc_maintain_cart_consistency'); function pc_maintain_cart_consistency() { if (!isset(WC()->session) || !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['snapshot'])) return; // 立即恢复完整购物车以确保UI一致性 pc_restore_cart_from_items($payload['snapshot']['items']); pc_restore_cart_coupons($payload['snapshot']['coupons']); WC()->cart->calculate_totals(); } // 在 functions.php 中添加折扣过滤器 add_filter('pc_dynamic_discount', function($price, $cart_item) { // 这里是您的动态折扣计算逻辑 // 示例:应用10%折扣 return $price * 0.9; }, 10, 2); It says There has been a critical error on this website. Which part gets wrong?
最新发布
09-10
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值