My ecommerce works like this: I have some downloadable products which have a list of files attached to it, available for downloads.
However I need to filter the downloads available according to the selection the user will make when adding to cart. These options need to be stored in order to filter the downloads available to the customers according to the selected options. So comparing the name of the download file against the strings in the array should do the trick.
Example: The download product contains downloads called Weight 1, Weight 2, Weight 3, etc.. The user selects Weight 1 and Weight 3 when adding to cart. The user only gets these the files called Weight 1 and Weight 3.
So far, these selections are successfully stored into product item meta data as an array of strings. Using the following functions inside functions.php:
// save selected weights into meta for minicart
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;
// below statement make sure every add to cart action as unique line item
$cart_item_data['unique_key'] = md5( microtime().rand() );
WC()->session->set( 'session_fw', $fw );
}
return $cart_item_data;
}
// output custom Item value in Cart and Checkout pages
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;
}
// save cart item custom meta as order item meta data and display it everywhere on orders and email notifications.
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', $values['selected_font_weights']);
}
$product_id = $item['product_id'];
$w = get_post_meta( $product_id, 'selected_font_weights', true );
wc_add_order_item_meta($item, 'Selected weights', $w , true);
}
In this way the data is accessible all the way to the "Order received" page. What I'm struggling now is to filter the downloads available in this page and in the email, etc.. according to Is there a hook to filter the downloads by comparing the filename to the strings listed inside the array?
There are some mistakes and unnecessary things in your code. Use the following instead:
// save selected weights as custom cart item data
add_filter( 'woocommerce_add_cart_item_data', 'save_font_weights' );
function save_font_weights( $cart_item_data ) {
if( isset($_POST['font_weights']) && !empty($_POST['font_weights']) ) {
$cart_item_data['font_weights'] = wc_clean($_POST['font_weights']);
$cart_item_data['unique_key'] = md5( microtime().rand() );
}
return $cart_item_data;
}
// Display custom cart item data in mini cart, Cart and Checkout pages
add_filter( 'woocommerce_get_item_data', 'output_font_weights', 10, 2 );
function output_font_weights( $cart_data, $cart_item ) {
if( isset($cart_item['font_weights']) ) {
$cart_data[] = array(
'key' => __('Selected weights', 'woocommerce'),
'value' => $cart_item['font_weights']
);
}
return $cart_data;
}
// save cart item custom data as order item metadata and display it everywhere on orders and email notifications.
add_action( 'woocommerce_checkout_create_order_line_item', 'save_weights_to_order_item', 10, 4 );
function save_weights_to_order_item( $item, $cart_item_key, $values, $order ) {
if( isset($values['font_weights']) ) {
$item->update_meta_data( 'Selected weights', $values['font_weights']);
}
}
Below I use 2 new functions in addition to the existing code:
$some_variable_to_replace
with the correct variable to be compared to your array of selected weightsNote: In the last function, I have listed first all the data that you can get from each download item, into variables that you can use.
The additional functions:
// save cart item custom data by product as order metadata
add_action( 'woocommerce_checkout_create_order', 'save_weights_to_order' );
function save_weights_to_order( $order ) {
$weights_by_product = array(); // Initializing
// Loop through cart items
foreach( WC()->cart->get_cart() as $item ) {
if( isset($item['font_weights']) ) {
$font_weights = str_replace(', ', ',', $item['font_weights']); // removing white spaces
$font_weights = explode(',', $font_weights); // converting to an array
$weights_by_product[$item['data']->get_id()] = $font_weights;
}
}
if( !empty($weights_by_product) ) {
// save weights as order metadata
$order->update_meta_data( '_selected_weights', $weights_by_product);
}
}
// filter downloadable items
add_filter( 'woocommerce_order_get_downloadable_items', 'filter_order_downloadable_items', 10, 2 );
function filter_order_downloadable_items( $downloads, $order ) {
foreach ( $downloads as $key => $download ) {
// All available data in the $download variable
$download_url = $download['download_url'];
$file_name = $download['file']['name'];
$file = $download['file']['file'];
$download_id = $download['download_id'];
$product_id = $download['product_id'];
$product_name = $download['product_name'];
$product_url = $download['product_url'];
$download_name = $download['download_name'];
$order_id = $download['order_id'];
$order_key = $download['order_key'];
$downloads_remaining = $download['downloads_remaining'];
$access_expires = $download['access_expires'];
// Get all selected weights by product
if ( $weights_by_product = $order->get_meta('_selected_weights') ) {
// Get the selected weights for the product ID
$selected_weights = (array) $weights_by_product[$product_id];
// Here below, REPLACE $some_variable_to_replace with the correct variable
if ( ! in_array( $some_variable_to_replace, $selected_weights ) ) {
unset($downloads[$key]); // Remove the font weight if not selected
}
}
}
return $downloads;
}
Code goes in functions.php file of tour child theme (or in a plugin). It should work.