
本文详解为何 `wp_query` 的 `category_name` 参数无法用于 woocommerce 商品分类,以及如何通过 `tax_query` 正确筛选指定 `product_cat` 分类下的商品,并提供可直接复用的短代码实现与关键注意事项。
WooCommerce 的商品(product)并不使用 WordPress 默认的 category 分类法(taxonomy),而是自定义了独立的分类体系 product_cat。因此,直接使用 'category_name' => 'gry' 这类面向文章分类(category)的参数,在查询商品时完全无效——这正是你遇到“无结果返回”且 get_the_category() 返回空数组的根本原因:get_the_category() 仅适用于 post 类型,对 product 不适用。
要精准按商品分类查询,必须使用 tax_query 显式指定 taxonomy => 'product_cat'。以下是修正后的短代码完整实现(已优化性能、安全性与可维护性):
function test_short($attr) {
$atts = shortcode_atts(array(
'cat' => 'gry', // 支持传入单个分类名,如 [test_short cat="gry"]
), $attr);
$args = array(
'post_type' => 'product',
'post_status' => 'publish',
'posts_per_page' => -1,
'tax_query' => array(
array(
'taxonomy' => 'product_cat',
'field' => 'slug', // 推荐用 slug 而非 name,更稳定(避免多语言/特殊字符问题)
'terms' => $atts['cat'],
),
),
'suppress_filters' => true,
);
$wc_query = new WP_Query($args);
$content = '';
// 引入 Swiper JS(建议移至 enqueue_scripts,此处为兼容演示)
$content .= '<script src="https://unpkg.com/swiper/swiper-bundle.min.js"></script>';
$content .= '<div class="swiper slidee">
<div class="swiper-wrapper">';
if ($wc_query->have_posts()) {
while ($wc_query->have_posts()) {
$wc_query->the_post();
$id = get_the_ID();
$title = get_the_title();
$price = wc_get_price_html(); // 更安全:自动处理价格格式与促销价
$url = wp_get_attachment_image_url(get_post_thumbnail_id($id), 'woocommerce_thumbnail') ?: wc_placeholder_img_src();
$content .= '<div class="swiper-slide">';
$content .= '<img class="product_img" src="' . esc_url($url) . '" alt="' . esc_attr($title) . '">';
$content .= '<div class="title">' . esc_html($title) . '</div>';
$content .= '<div class="price">' . $price . '</div>';
$content .= '<a href="' . esc_url(wc_get_cart_url()) . '?add-to-cart=' . $id . '"
data-quantity="1"
class="button product_type_simple add_to_cart_button ajax_add_to_cart"
data-product_id="' . $id . '"
aria-label="' . esc_attr(sprintf(__('Add “%s” to cart', 'woocommerce'), $title)) . '"
rel="nofollow">
<span>' . esc_html__('Add to cart', 'woocommerce') . '</span>
</a>';
$content .= '</div>';
}
} else {
$content .= '<div class="swiper-slide"><p>' . esc_html__('No products found in this category.', 'woocommerce') . '</p></div>';
}
$content .= '</div>
<div class="swiper-button-next"></div>
<div class="swiper-button-prev"></div>
</div>';
// 初始化 Swiper(注意:需确保 DOM 已就绪,建议用 document.addEventListener('DOMContentLoaded', ...) 包裹)
$content .= '<script>
document.addEventListener("DOMContentLoaded", function() {
if (typeof Swiper !== "undefined") {
new Swiper(".slidee", {
slidesPerView: 3.5,
spaceBetween: 30,
autoplay: { delay: 3000 },
speed: 1700,
navigation: {
nextEl: ".swiper-button-next",
prevEl: ".swiper-button-prev"
}
});
}
});
</script>';
wp_reset_postdata(); // ✅ 关键!替代已废弃的 wp_reset_query()
return $content;
}
add_shortcode('test_short', 'test_short');关键注意事项:
- ✅ 始终用 wp_reset_postdata():WP_Query 后必须调用此函数恢复主循环全局变量,wp_reset_query() 仅适用于 query_posts()(已不推荐)。
- ✅ 优先使用 slug 而非 name:分类别名(slug)唯一且稳定;中文或带空格的分类名在 name 模式下易出错。可通过后台 URL 或数据库确认 slug(如 gry 对应 gry,而非 Gry)。
- ✅ 验证分类是否存在:调试时可临时添加 var_dump(get_terms(['taxonomy' => 'product_cat', 'slug' => $atts['cat']])); 确认分类有效。
- ⚠️ 避免内联脚本风险:file_get_contents(get_site_url().'/javascript.js') 存在路径错误与安全风险,应改用 wp_enqueue_script() 注册并加载 JS。
- ? 输出内容务必转义:所有动态插入的 HTML 属性(如 src, href, alt)均使用 esc_url() / esc_html() 防止 XSS。
通过以上修正,你的短代码即可稳定按 WooCommerce 商品分类拉取数据,并与 Swiper 无缝集成。










