
为什么选择 wc_get_products 而非 WP_Query
在woocommerce中构建自定义产品查询时,官方强烈推荐使用 wc_get_products 和 wc_product_query,而非传统的 wp_query 或直接的数据库查询。这是因为woocommerce未来可能会将产品数据迁移到自定义表中以提升性能,而 wc_get_products 提供了一个标准且安全的接口,能够确保代码的未来兼容性,避免因数据库结构变化导致代码失效。当我们需要在自定义模板中仅显示特定分类下的产品时,wc_get_products 是实现这一目标的最佳实践。
创建自定义 WooCommerce 产品归档模板
首先,为了实现自定义的产品展示逻辑,我们需要创建一个自定义的WooCommerce模板。
复制基础模板: 将 woocommerce/archive-product.php 文件复制到你的子主题的 woocommerce 文件夹中。
-
重命名并添加模板注释: 将复制的文件重命名为,例如 custom-category-archive.php。然后,在文件顶部添加模板注释,使其可以作为页面模板在WordPress后台选择:
通过这种方式,你可以在WordPress页面编辑界面中选择这个模板来展示特定内容。
构建按分类 ID 筛选的自定义产品循环
在 custom-category-archive.php 模板中,我们将替换或修改标准的WooCommerce产品循环,以使用 wc_get_products 来筛选特定分类的产品。
标准的WooCommerce产品循环通常如下所示:
主要特点为模板驱动,前台页面和数据库数据在模板中以标签方式调用和显示。星期三企业建站系统产品全部代码都为星期三网络原创,有着完全的知识产权。我们会已我们的努力使星期三企业建站系统变的更好!系统功能1\网站信息设置2\菜单管理3\系统页面4\幻灯片管理5\友情链接6\商品分类 7\商品管理 8\资讯分类 9\资讯管理 10\自定义页面分类 11\自定义页面 12\留言管理 13\下载管理 14\选择
if ( woocommerce_product_loop() ) {
do_action( 'woocommerce_before_shop_loop' );
woocommerce_product_loop_start();
if ( wc_get_loop_prop( 'total' ) ) {
while ( have_posts() ) {
the_post();
do_action( 'woocommerce_shop_loop' );
wc_get_template_part( 'content', 'product' );
}
}
woocommerce_product_loop_end();
}要按分类ID筛选,我们将用 wc_get_products 构建一个全新的循环。以下是完整的代码示例,你可以在 custom-category-archive.php 文件中 get_header( 'shop' ); 之后,do_action( 'woocommerce_before_main_content' ); 之前或之后添加:
query->get_catalog_ordering_args();
$ordering['orderby'] = array_shift( explode( ' ', $ordering['orderby'] ) );
// 根据排序字段调整 orderby 参数,例如价格排序需要特殊处理
$ordering['orderby'] = stristr( $ordering['orderby'], 'price' ) ? 'meta_value_num' : $ordering['orderby'];
// 定义 wc_get_products 的查询参数
$args = array(
'status' => 'publish', // 只获取已发布的产品
'limit' => -1, // 获取所有匹配的产品,不限制数量
'paginate' => true, // 启用分页,方便获取总数
'return' => 'ids', // 只返回产品ID,减少内存消耗,提高性能
'orderby' => $ordering['orderby'], // 继承WooCommerce的排序方式
'order' => $ordering['order'], // 继承WooCommerce的排序顺序
'tax_query' => array(
array(
'taxonomy' => 'product_cat', // 针对产品分类
'field' => 'term_id', // 通过分类ID进行查询
'terms' => array( 12, 345, 7899 ), // 指定要包含的分类ID,请替换为你的实际ID
'operator' => 'IN', // 包含在指定ID列表中的分类
)
),
// 其他可选参数,例如库存状态和可见性
// 'stock_status' => 'instock', // 只显示有库存的产品
// 'visibility' => 'visible', // 只显示可见的产品
);
// 执行产品查询
$cat_products = wc_get_products( $args );
// 设置循环属性,确保WooCommerce的其他组件(如结果计数、分页)能正确工作
wc_set_loop_prop( 'total', $cat_products->total );
wc_set_loop_prop( 'total_pages', $cat_products->max_num_pages ); // 如果需要分页,设置总页数
// 检查是否有产品
if ( $cat_products && ! empty( $cat_products->products ) ) {
do_action( 'woocommerce_before_shop_loop' );
echo ''; // 自定义容器,可根据需要修改
foreach ( $cat_products->products as $product_id ) {
// 获取产品对象并设置全局 $post 变量
$post_object = get_post( $product_id );
setup_postdata( $GLOBALS['post'] =& $post_object );
// 获取产品实例,用于 wc_product_class
$product = wc_get_product( $product_id );
// 渲染单个产品内容,利用WooCommerce的钩子和模板部分
echo '';
do_action( 'woocommerce_before_shop_loop_item' ); // 产品循环项开始前的钩子
do_action( 'woocommerce_before_shop_loop_item_title' ); // 产品标题前的钩子
do_action( 'woocommerce_shop_loop_item_title' ); // 产品标题钩子
do_action( 'woocommerce_after_shop_loop_item_title' ); // 产品标题后的钩子
do_action( 'woocommerce_after_shop_loop_item' ); // 产品循环项结束后的钩子
echo '';
}
wp_reset_postdata(); // 重置全局 $post 变量,避免影响后续查询
echo ''; // 结束自定义容器
do_action( 'woocommerce_after_shop_loop' );
} else {
// 如果没有找到产品
do_action( 'woocommerce_no_products_found' );
}
do_action( 'woocommerce_after_main_content' );
get_footer( 'shop' );关键参数解析与注意事项
-
wc_get_products($args) 参数:
- status: 查询产品的状态,如 publish(已发布)。
- limit: 每页显示的产品数量。设置为 -1 表示不限制,获取所有匹配产品。
- paginate: 设置为 true 时,wc_get_products 会返回一个 WC_Product_Query 对象,其中包含 total(总产品数)和 max_num_pages(总页数),这对于正确显示分页和结果计数至关重要。
- return: 指定返回值的类型。设置为 ids 可以只返回产品ID数组,这在仅需遍历产品并渲染时能有效减少内存消耗。
- orderby 和 order: 用于控制产品排序。示例中继承了WooCommerce商店页面的默认排序设置。
- tax_query: 这是实现按分类筛选的核心。它是一个数组,每个元素定义一个分类法查询。
- taxonomy: 指定分类法的名称,对于产品分类,通常是 product_cat。
- field: 指定用于查询的分类字段,term_id 表示通过分类ID。
- terms: 一个数组,包含你希望包含(或排除)的分类ID。请注意,这里的ID应为整数,如 array(12, 345, 7899)。
- operator: 操作符,如 IN(包含在列表内)、NOT IN(不包含在列表内)等。
wc_set_loop_prop('total', $cat_products->total);: 这一行代码非常重要。它将自定义查询获取的产品总数传递给WooCommerce的全局循环属性。这样,woocommerce_result_count 等钩子函数才能正确显示“显示 x 到 y 共 z 个结果”这样的信息,并且分页功能也能基于正确的产品总数进行计算。
-
循环迭代与产品渲染:
- foreach ( $cat_products->products as $product_id ): 遍历 wc_get_products 返回的产品ID。
- setup_postdata( $GLOBALS['post'] =& $post_object );: 这一步是关键!它将当前产品ID对应的 WP_Post 对象设置为全局 $post 变量,使得所有依赖于 $post 变量的WordPress和WooCommerce模板函数(如 the_title()、the_permalink()、wc_get_template_part() 等)都能正确获取到当前产品的数据。
- wp_reset_postdata();: 在循环结束后,务必调用此函数,以将全局 $post 变量恢复到主查询的状态,避免影响页面其他部分的查询。
- do_action(...): 利用WooCommerce提供的各种动作钩子,可以方便地在产品循环的各个阶段插入自定义内容或调用WooCommerce的默认渲染函数,如 wc_get_template_part( 'content', 'product' );(在自定义循环中,我们手动调用了多个子钩子来模拟 content-product.php 的渲染)。
-
获取分类ID: 在示例中,分类ID是硬编码的 array( 12, 345, 7899 )。在实际应用中,这些ID可能需要动态获取,例如:
- 从URL参数获取。
- 从自定义字段(如 ACF)获取。
- 通过 get_term_by() 函数根据分类名称或 slug 获取 ID。
总结
通过 wc_get_products 函数,我们可以强大而灵活地控制WooCommerce产品循环,实现按分类ID筛选等复杂需求,同时保持与WooCommerce未来版本的兼容性。在构建自定义模板时,理解 wc_get_products 的参数、wc_set_loop_prop 的作用以及 setup_postdata/wp_reset_postdata 的必要性,将帮助你创建高效、健壮且易于维护的WooCommerce解决方案。始终优先使用官方推荐的 wc_get_products 接口,以确保你的代码在长期运行中的稳定性和性能。









