返回

WooCommerce 商品列表页变量商品属性优化显示

php

WooCommerce 商品列表页变量商品属性值的优化显示

在 WooCommerce 商店中,让客户快速了解商品的各种属性至关重要。直接在商品列表页,比如归档页和分类页上显示属性,可以提升购物体验,减少客户点击到具体商品页面去查看的次数。对于简单商品,提取并显示属性通常很容易;但对于变量商品,情况就要复杂一些,可能会遇到一些挑战。下面介绍如何处理变量商品属性值的优化显示,避免某些缺货变体属性也展示的问题。

问题分析

直接提取变量商品的属性值存在一个问题:这可能获取到所有变体的属性值,不论这个变体库存是多少,是“有货”还是“缺货”。当某个变体的库存为零时,在商品列表页仍可能显示出该变体的属性,给顾客造成困扰,误以为还能购买,造成用户体验不好。正确的做法是,只显示尚有库存的变体属性。

解决方案

解决思路是获取所有有库存的变体的属性,过滤掉库存为零的变体。主要使用 WooCommerce 的 get_available_variations() 方法。修改原来的 new_template_loop_product_meta() 函数来实现更精确的属性显示。

操作步骤如下:

  1. 获取所有变体: 使用get_available_variations() 获取所有可用变体数据。

  2. 筛选属性: 遍历可用变体,提取指定属性。

  3. 去重并排序: 对提取的属性值进行去重和排序操作,确保相同属性值的多个变体仅显示一个值,并按自然排序规则排列。

  4. 显示属性: 将处理后的属性值展示在页面上。

改进代码

改进new_template_loop_product_meta()函数中原来的输出:

add_action( 'woocommerce_before_shop_loop_item_title', 'new_template_loop_product_meta', 20 );
function new_template_loop_product_meta() {
    global $product;

    $attrs_by_cats = [
        20 => [ 'pa_size' ],
    ];

    $attr_list = [
        'Size' => 'pa_size',
    ];

    if ( ! is_object( $product ) ) {
        $product = wc_get_product( get_the_id() );
    }

    $cats = $product->get_category_ids();

    if ( ! is_array( $cats ) ) {
        return;
    }

    $attrs = [];

    foreach ( $cats as $cat ) {
        if ( isset( $attrs_by_cats[ $cat ] ) ) {
            $attrs[] = $attrs_by_cats[ $cat ];
        }
    }

    $allowed_attrs = array_unique( array_merge( [], ...$attrs ) );

    echo '<div class="custom-attributes">';

    foreach ( $attr_list as $attr_title => $attr_name ) {
        if ( in_array( $attr_name, $allowed_attrs, true ) ) {
           
            // show_attribute( $product, $attr_title, $attr_name ); 
            // 替换成下面
            if( $product->is_type('variable')){
                show_variable_attribute( $product, $attr_title, $attr_name);
            } else {
                show_attribute( $product, $attr_title, $attr_name );
            }

        }
    }

    echo '</div>';
}

/* 新增函数: 专门处理可变商品的属性 */
function show_variable_attribute( $product, $attr_title, $attr_name ) {
    $variations = $product->get_available_variations();
    $attribute_values = [];

    foreach ( $variations as $variation ) {
        if( isset($variation['attributes']['attribute_' . $attr_name])  && $variation['is_in_stock'] == true){ // 确保该变体存在指定的属性值, 且该变体有库存

            $attribute_value = $variation['attributes']['attribute_' . $attr_name];
        
            if ( ! empty( $attribute_value ) ) {
                $attribute_values[] = $attribute_value;
            }
        }
        
    }
    
    // 去重排序
    $unique_values = array_unique( $attribute_values );
    natsort($unique_values);

    // 没有需要展示的属性时直接退出函数
    if( empty($unique_values)){
        return;
    }

    $attribute_string = '';

    foreach( $unique_values as $term_name ){
         $attribute_string .= sprintf('<span class="attr-term">%s</span>', $term_name);
    }
    
    printf( '<div class="custom-attributes-text">%s: %s</div>', $attr_title, $attribute_string);
}

/* 原有函数, 展示简单商品属性, 不做改动 */
function show_attribute( $product, $attr_title, $attr_name ) {
    // ... 代码保持原样 ...
}

代码解释:

  • show_variable_attribute() 函数专门处理变量商品。它获取所有可购买的变体。对每个变体,判断该变体是否有指定的属性,且该变体有库存;满足条件后读取属性的值,把值加入到 $attribute_values 数组中。去重、排序,最后显示在商品列表页。

安全建议

  • 数据验证: 在显示属性值之前,进行数据验证,避免安全问题。
  • 避免代码注入: sprintf()esc_html() 函数可以提供保护,避免一些代码注入漏洞。在修改上述代码的时候,需要谨慎思考每个变量的用法,小心处理用户提供的数据。

优化

为了提升效率和代码可读性,还有几点优化措施:

  1. 缓存 : 如果属性很少变动,可以考虑对属性结果进行缓存,以减少数据库查询次数,加快页面加载速度。可以根据自身需要增加刷新缓存的机制。
  2. 按需加载 : 根据业务的实际需求来考虑按需加载的策略。比如用户翻页浏览很多产品数据的时候。
  3. 优化$attrs_by_cats变量 : 按实际业务要求维护此变量, 不要在此变量里填入无关的类目。避免引入过多无用计算量。