如何通过Woocommerce钩子依据元数据筛选订单内可下载文件?
基于用户选择筛选WooCommerce可下载产品的附件
问题背景
我用WooCommerce搭建电商网站,部分产品是带有多个附件的可下载产品。需要根据用户加购时选择的选项,通过文件名与选项数组的字符串匹配,筛选用户能获取的下载文件。比如产品有“Weight 1、Weight 2、Weight 3”的下载文件,用户选了“Weight 1”和“Weight 3”,就只让他们获取这两个文件。
目前已经通过functions.php里的代码,把用户选择的选项成功存为订单项元数据数组:
// 保存选中的权重到购物车元数据 add_filter( 'woocommerce_add_cart_item_data', 'save_font_weights', 10, 3 ); function save_font_weights( $cart_item_data, $product_id, $variation_id ) { $fw = $_POST['font_weights']; if( !empty($fw) ) { $cart_item_data[ 'selected_font_weights' ] = $fw; // 确保每次加购都是独立订单项 $cart_item_data['unique_key'] = md5( microtime().rand() ); WC()->session->set( 'session_fw', $fw ); } return $cart_item_data; } // 在购物车和结账页面显示自定义选项 add_filter( 'woocommerce_get_item_data', 'output_font_weights', 10, 2 ); function output_font_weights( $cart_data, $cart_item ) { if( isset( $cart_item['selected_font_weights'] ) ) { $cart_data[] = array( 'key' => __('Selected weights', 'woocommerce'), 'value' => $cart_item['selected_font_weights'], 'display' => $cart_item['selected_font_weights'], ); } return $cart_data; } // 将购物车自定义元数据保存为订单项元数据,在订单和邮件中显示 add_action( 'woocommerce_checkout_create_order_line_item', 'save_weights_to_order', 10, 4 ); function save_weights_to_order( $item, $cart_item_key, $values, $order ) { if( isset($values['selected_font_weights']) && ! empty($values['selected_font_weights']) ) { // 去除原代码冗余操作,避免重复添加元数据 $item->update_meta_data( __('Selected weights', 'woocommerce'), $values['selected_font_weights']); } }
解决方案:使用woocommerce_order_item_get_downloads钩子筛选下载文件
WooCommerce提供了woocommerce_order_item_get_downloads过滤器,专门用来修改订单项的可下载文件列表。你可以通过这个钩子,结合已保存的订单项元数据,匹配文件名来筛选下载文件:
// 根据用户选择的选项筛选可下载文件 add_filter( 'woocommerce_order_item_get_downloads', 'filter_downloads_by_selected_weights', 10, 2 ); function filter_downloads_by_selected_weights( $downloads, $item ) { // 获取订单项中保存的选中权重 $selected_weights = $item->get_meta( 'Selected weights' ); // 如果没有选中的权重,直接返回原下载列表 if ( empty( $selected_weights ) ) { return $downloads; } // 将选中的权重转为数组(如果存储的是逗号分隔字符串) if ( is_string( $selected_weights ) ) { $selected_weights = array_map( 'trim', explode( ',', $selected_weights ) ); } // 筛选下载文件:文件名包含选中权重中的任意一个 $filtered_downloads = array_filter( $downloads, function( $download ) use ( $selected_weights ) { $filename = pathinfo( $download->get_file(), PATHINFO_FILENAME ); // 检查文件名是否匹配选中权重 foreach ( $selected_weights as $weight ) { // PHP版本低于8.0时,替换为strpos($filename, $weight) !== false if ( str_contains( $filename, $weight ) ) { return true; } } return false; }); return $filtered_downloads; }
代码说明
- 钩子作用:
woocommerce_order_item_get_downloads会在获取订单项下载文件列表时触发,允许修改返回的下载项数组。 - 元数据获取:通过
$item->get_meta('Selected weights')读取之前保存的用户选择选项。 - 格式转换:如果存储的是逗号分隔字符串,转为数组方便后续匹配操作。
- 文件筛选:用
array_filter遍历所有下载文件,检查文件名(不含扩展名)是否包含选中的权重字符串,仅保留匹配项。 - 版本兼容:
str_contains适用于PHP 8.0+,低版本PHP可替换为strpos($filename, $weight) !== false。
内容的提问来源于stack exchange,提问作者ilariaroglieri
相关产品推荐
相关产品推荐

