Last active
March 19, 2024 10:05
-
-
Save doubleedesign/8936eb1194f5ca608e1325696b2546f6 to your computer and use it in GitHub Desktop.
Export selected data about the currently shown WooCommerce orders to a CSV file
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Function to export the orders list to a CSV download (not stored anywhere) | |
* CSV construction based on https://gist.github.com/vrushank-snippets/4274500 | |
* Dev notes: | |
* - This file is designed to be called via AJAX, with that function providing the order IDs. | |
* - To use this without AJAX you would just need to define $order_ids = wp_list_pluck($wp_query->posts, 'ID') instead, | |
* and define $filename as something appropriate here. | |
*/ | |
function doublee_export_orders() { | |
$order_ids = json_decode($_POST['order_ids']); | |
$results = array(); | |
// Check security nonce from AJAX request | |
if (!check_ajax_referer('exporter-nonce', 'security', false)) { | |
wp_send_json_error('Invalid security token sent.'); | |
wp_die(); | |
} | |
if(is_admin() && !empty($order_ids)) { | |
// For each order: | |
foreach ($order_ids as $order_id) { | |
$order = wc_get_order($order_id); | |
// Get data we want to export | |
$user_id = $order->get_user_id(); | |
$user_name = get_user_meta($user_id, 'first_name', true).' '.get_user_meta( $user_id, 'last_name', true ); | |
$products = doublee_get_order_products($order_id); | |
$products_ordered = implode(', ', $products); // Comma-separated list of product names | |
$order_date = $order->get_date_created()->getTimestamp(); | |
$order_date_formatted = date( 'd/m/Y' ); | |
$status = $order->get_status(); | |
// Put it all into an array | |
$order_data = array( | |
'Order ID' => $order_id, | |
'Customer name' => $user_name, | |
'Product(s)' => $products_ordered, | |
'Order date' => $order_date_formatted, | |
'Status' => $status | |
); | |
// Add it to the $results array | |
$results[$order_id] = $order_data; | |
} | |
// Temp name for the CSV file | |
$filename = 'temp.csv'; | |
// Set headers for the CSV file download | |
header( "Cache-Control: must-revalidate, post-check=0, pre-check=0" ); | |
header( 'Content-Description: File Transfer' ); | |
header( "Content-type: text/csv" ); | |
header( "Content-Disposition: attachment; filename={$filename}" ); | |
header( "Expires: 0" ); | |
header( "Pragma: public" ); | |
// Open the file | |
$fh = fopen( 'php://output', 'w' ); | |
// When we first begin, the file doesn't have the header row | |
$headerDisplayed = false; | |
// Loop through the data array and add rows to the file | |
foreach ($results as $data) { | |
// Add a header row if it hasn't been added yet | |
if (!$headerDisplayed) { | |
// Use the keys from $data as the titles | |
fputcsv($fh, array_keys($data)); | |
$headerDisplayed = true; | |
} | |
// Put the data into the stream | |
fputcsv($fh, $data); | |
} | |
// Close the file | |
fclose($fh); | |
} | |
exit(); | |
} | |
add_action('wp_ajax_doublee_export_orders', 'doublee_export_orders'); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* The export function is called via AJAX for a smooth admin experience, but has no awareness of what page it's on and hence the current query. | |
* This function makes the current query's order IDs available to the JavaScript file so the AJAX function can send which order IDs it wants to export. | |
* Here we also set a limit on how many can be exported at once, to prevent timeouts, | |
* and let the script know what page we're on for file naming purposes ($wp_query accounts for the number of items per page set in Screen Options). | |
* The other localised variables are here too because having wp_localize_script run more than once causes only the last one to be used. | |
*/ | |
function doublee_make_current_order_ids_ajaxable() { | |
if(current_user_can('manage_woocommerce')) { | |
global $wp_query; | |
$query_limit = 50; | |
$all_ids = wp_list_pluck($wp_query->posts, 'ID'); | |
$limit_exceeded = false; | |
if(count($all_ids) > $query_limit) { | |
$limit_exceeded = true; | |
} | |
$page = '1'; | |
if($wp_query->query['paged'] > 1) { | |
$page = $wp_query->query['paged']; | |
} | |
wp_localize_script('order-export', 'doubleedesign', array( | |
'ajaxurl' => admin_url('admin-ajax.php'), | |
'security' => wp_create_nonce('exporter-nonce'), | |
'order_ids' => array_slice($all_ids, '0', 50), | |
'export_limit' => $query_limit, | |
'export_limit_exceeded' => $limit_exceeded, | |
'result_page' => $page | |
)); | |
} | |
} | |
add_action('wp', 'doublee_make_current_order_ids_ajaxable', 50); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
jQuery(document).ready(function($) { | |
$('#export-orders-button').on('click', function(event) { | |
event.preventDefault(); | |
var default_label = $(this).text(); | |
// Check that there's actually orders to export before proceeding. | |
if(doubleedesign.order_ids.length === 0) { | |
alert('Please select some orders to export'); | |
return; | |
} | |
// Show message if limit is exceeded (limit exists to prevent timeouts) | |
if(doubleedesign.export_limit_exceeded == true) { | |
alert('Please select a maximum of 50 orders to export at a time'); | |
return; | |
} | |
// Set filename | |
var today = new Date(); | |
var filename = 'Orders-' + today.toISOString().substring(0, 10) + '--Page-' + doubleedesign.result_page + '.csv'; | |
// Add loading state | |
$(this).addClass('loading'); | |
$(this).text('Exporting orders'); | |
// Ajax function to run the export | |
$.ajax({ | |
method: 'POST', | |
dataType: 'text', | |
url: doubleedesign.ajaxurl, | |
data: { | |
action: 'doublee_export_orders', | |
security: doubleedesign.security, | |
order_ids: JSON.stringify(doubleedesign.order_ids) | |
}, | |
success: function (response) { | |
// Make CSV in the response downloadable by creating a blob | |
var download_link = document.createElement("a"); | |
var fileData = ['\ufeff'+response]; | |
var blobObject = new Blob(fileData,{ | |
type: "text/csv;charset=utf-8;" | |
}); | |
// Actually download the CSV by temporarily creating a link to it and simulating a click | |
download_link.href = URL.createObjectURL(blobObject); | |
download_link.download = filename; | |
document.body.appendChild(download_link); | |
download_link.click(); | |
document.body.removeChild(download_link); | |
// Remove the export button's loading state | |
$('#export-orders-button').removeClass('loading').text(default_label); | |
}, | |
error: function(response) { | |
console.log(response); | |
$('#export-orders-button').removeClass('loading').addClass('error').text('Error exporting'); | |
}, | |
}) | |
}) | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Utility function to get the product names (not every order item - disregard product addons) in an order | |
* as Product ID => Name pairs | |
* @param $order_id | |
* | |
* @return array | |
*/ | |
function doublee_get_order_products($order_id) { | |
$order = wc_get_order($order_id); | |
$items = $order->get_items(); | |
// Each product format (which is a Product Addon) shows up as an order item. | |
// Get just the products by looping through and getting the product IDs | |
$product_ids = array(); | |
foreach($items as $item) { | |
array_push($product_ids, $item->get_product_id()); | |
} | |
// Only include each product once, not for every addon | |
$product_ids = array_unique($product_ids); | |
// Create an array of product ID => name pairs | |
$product_list = array(); | |
foreach($product_ids as $product_id) { | |
$product = wc_get_product($product_id); | |
if($product) { | |
$product_list[$product_id] = $product->get_name(); | |
} | |
} | |
// Return that array | |
return $product_list; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment