Last active
April 5, 2024 16:10
-
-
Save damiencarbery/d387d7ee2d860789030347eb68b11589 to your computer and use it in GitHub Desktop.
A quick proof of concept of using an order ID to generate a CSV of order details.
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 | |
/* | |
Plugin Name: WooCommerce - Export order details as CSV | |
Plugin URI: https://www.damiencarbery.com/ | |
Description: Allow exporting the details . | |
Author: Damien Carbery | |
Author URI: https://www.damiencarbery.com | |
Version: 0.1 | |
*/ | |
/* | |
https://stackoverflow.com/questions/4545311/download-a-file-by-jquery-ajax | |
https://codepen.io/chrisdpratt/pen/RKxJNo | |
https://stackoverflow.com/questions/4545311/download-a-file-by-jquery-ajax | |
*/ | |
//add_action( 'wp_ajax_nopriv_ajax_code_generator_name', 'ajax_export_order_csv_func' ); | |
add_action( 'wp_ajax_export_order_csv', 'ajax_export_order_csv_func' ); | |
add_filter( 'woocommerce_order_item_add_action_buttons', 'dcwd_add_export_order_csv_button' ); | |
function dcwd_add_export_order_csv_button( $order ) { | |
//error_log( 'Order ID: : ' . $email_heading ); | |
//printf( '<a href="?order_id=%d">Export CSV</a>', $order->get_id() ); | |
printf( '<button type="button" class="button export-csv">%s</button>', esc_html( 'Export CSV (ajax)', 'woocommerce' ) ); | |
printf( '<a href="%s%d"><button type="button" class="button export-csv-link">%s</button></a>', 'http://localhost/woo-hpos/wp-json/export-order-csv/v1/export-order-csv/', $order->get_id(), esc_html( 'Export CSV (REST API)', 'woocommerce' ) ); | |
add_action( 'admin_footer', 'dcwd_add_export_order_csv_js' ); | |
} | |
function get_order_data_as_csv( $order_id ) { | |
$order_csv = array(); | |
$order = wc_get_order( $order_id ); | |
if ( $order ) { | |
// Add billing details on separate lines (each line is an array [within an array]). | |
$order_csv[] = array( $order->get_billing_first_name(), $order->get_billing_last_name() ); | |
$line = $order->get_billing_company(); | |
if ( ! empty( $line ) ) { | |
$order_csv[] = array( $line ); | |
} | |
$order_csv[] = array( $order->get_billing_address_1() ); | |
$line = $order->get_billing_address_2(); | |
if ( ! empty( $line ) ) { | |
$order_csv[] = array( $line ); | |
} | |
$order_csv[] = array( $order->get_billing_city() ); | |
// Get full state name instead of abbreviation. | |
$order_csv[] = array( WC()->countries->states[ $order->get_billing_country() ][ $order->get_billing_state() ] ); | |
$order_csv[] = array( $order->get_billing_postcode() ); | |
// Get full country name instead of abbreviation. | |
$order_csv[] = array( WC()->countries->countries[ $order->get_billing_country() ] ); | |
$order_csv[] = array( $order->get_billing_email() ); | |
$order_csv[] = array( $order->get_billing_phone() ); | |
$order_csv[] = array(); // Add empty line before the items. | |
// Add product name and quantity on same line (stored as an array). | |
foreach ( $order->get_items() as $item_id => $item ) { | |
//$product_id = $item->get_product_id(); | |
//$variation_id = $item->get_variation_id(); | |
//$product = $item->get_product(); // see link above to get $product info | |
$product_name = $item->get_name(); | |
$quantity = $item->get_quantity(); | |
//$subtotal = $item->get_subtotal(); | |
//$total = $item->get_total(); | |
//$tax = $item->get_subtotal_tax(); | |
//$tax_class = $item->get_tax_class(); | |
//$tax_status = $item->get_tax_status(); | |
//$allmeta = $item->get_meta_data(); | |
//$somemeta = $item->get_meta( '_whatever', true ); | |
//$item_type = $item->get_type(); // e.g. "line_item", "fee" | |
$order_csv[] = array( $product_name, $quantity ); | |
} | |
} | |
return $order_csv; | |
} | |
function ajax_export_order_csv_func() { | |
//error_log( 'In ajax_export_order_csv_func().' ); | |
//error_log( '$_POST: ' . var_export( $_POST, true ) ); | |
if ( ! current_user_can( 'edit_shop_orders' ) ) { | |
wp_die( -1 ); | |
} | |
$order_id = intval( $_POST[ 'order_id' ] ); | |
$order_data = get_order_data_as_csv( $order_id ); | |
// Open raw memory as file, no need for temp files. | |
$f = fopen( 'php://memory', 'w' ); | |
// loop through array | |
foreach ($order_data as $line) { | |
// default php csv handler | |
fputcsv( $f, $line ); | |
} | |
// Rewrind the "file" with the csv lines | |
fseek($f, 0); | |
header('Content-Description: File Transfer'); | |
// Modify header to be downloadable csv file | |
header('Content-Type: text/csv'); | |
header('Content-Disposition: attachment; filename=order-' . $order_id . '.csv'); | |
// Send file to browser for download | |
fpassthru($f); | |
// wp_send_json_error(); | |
wp_die(); | |
} | |
function dcwd_add_export_order_csv_js() { | |
?> | |
<script> | |
jQuery(document).ready( function( $ ) { | |
jQuery( '.export-csv' ).on( 'click', function(e) { | |
//alert( 'Export CSV button clicked.' ); | |
e.preventDefault(); | |
jQuery.ajax({ | |
url : '<?php echo admin_url( 'admin-ajax.php' ); ?>', | |
type : 'post', | |
/*xhrFields: { | |
responseType: 'blob' | |
},*/ | |
data : { | |
action : 'export_order_csv', // Note that this is part of the add_action() call. | |
order_id: woocommerce_admin_meta_boxes.post_id, | |
// ToDo: Add nonce, maybe one on the same page. | |
//submitted_nonce : " . $ajax_js_object_name . ".the_nonce, | |
}, | |
success : function( data ) { | |
var uri = 'data:application/csv;charset=UTF-8,' + encodeURIComponent(data); | |
location.href = uri; | |
/*var disposition = response.getResponseHeader('Content-Disposition'); | |
console.log( 'disposition:', disposition ); | |
var matches = /"([^"]*)"/.exec(disposition); | |
console.log( 'matches:', matches ); | |
var filename = (matches != null && matches[1] ? matches[1] : 'order-export.csv'); | |
console.log( 'filename:', filename ); | |
var blob = new Blob([response.response], { type: 'text/csv' }); | |
var link = document.createElement('a'); | |
link.href = window.URL.createObjectURL(blob); | |
link.download = filename; | |
document.body.appendChild(link); | |
link.click(); | |
document.body.removeChild(link); | |
*/ | |
}, | |
error : function( response ) { | |
alert('Error retrieving the information: ' + response.status + ' ' + response.statusText); | |
console.log( response ); | |
} | |
}); | |
}); | |
}); | |
</script> | |
<?php | |
} | |
class ExportOrderCSVServer extends WP_REST_Controller { | |
private $api_namespace; | |
private $base; | |
private $api_version; | |
private $required_capability; | |
public function __construct() { | |
$this->api_namespace = 'export-order-csv/v'; | |
$this->base = 'export-order-csv'; | |
$this->api_version = '1'; | |
$this->required_capability = 'read'; // Minimum capability to use the endpoint | |
$this->init(); | |
} | |
public function register_routes() { | |
$namespace = $this->api_namespace . $this->api_version; | |
register_rest_route( $namespace, '/' . $this->base . '/(?P<id>[\d]+)', array( | |
array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'generate_order_csv' ), | |
'args' => array( 'id' => array( 'validate_callback' => function($param, $request, $key) { return is_numeric( $param ); } ), ), | |
'permission_callback' => '__return_true' ), | |
) ); | |
} | |
// Register our REST Server | |
public function init(){ | |
add_action( 'rest_api_init', array( $this, 'register_routes' ) ); | |
} | |
// From: https://stackoverflow.com/a/70008574/8605943 | |
public function generate_order_csv( WP_REST_Request $request ) { | |
$response = new WP_REST_Response; | |
$order_id = (int) $request['id']; | |
$response->set_data( $order_id ); | |
$response->set_headers( [ | |
'Content-Type' => 'text/csv', | |
//'Content-Length' => filesize( $path ), | |
'Content-Disposition' => 'attachment; filename=order-' . $order_id . '.csv', | |
] ); | |
//error_log( 'Set order id to ' . $request['id'] ); | |
// HERE → This filter will return the CSV content. | |
add_filter( 'rest_pre_serve_request', array( $this, 'generate_csv_data' ), 0, 4 ); | |
return $response; | |
} | |
// ToDo: Get more info from _oembed_rest_pre_serve_request() in wp-includes/embed.php | |
public function generate_csv_data( $served, $result, $request, $server ) { | |
$is_csv = false; | |
$order_id = null; | |
// Check the "Content-Type" header to confirm that we | |
// really want to return CSV data. | |
foreach ( $result->get_headers() as $header => $value ) { | |
if ( 'content-type' === strtolower( $header ) ) { | |
$is_csv = ( 0 === strpos( $value, 'text/csv' ) ); | |
$order_id = intval( $result->get_data() ); | |
break; | |
} | |
} | |
// Create the CSV output and tell the REST server to not send any other | |
// details (via "return true"). | |
if ( $is_csv && is_int( $order_id ) ) { | |
// ToDo: Generate CSV data here or earlier. | |
$order_data = get_order_data_as_csv( $order_id ); | |
// Open raw memory as file, no need for temp files. | |
$f = fopen( 'php://memory', 'w' ); | |
// loop through array | |
foreach ($order_data as $line) { | |
// default php csv handler | |
fputcsv( $f, $line ); | |
} | |
// Rewrind the "file" with the csv lines | |
fseek($f, 0); | |
// Send file to browser for download | |
fpassthru($f); | |
return true; | |
} | |
return $served; | |
} | |
} | |
$export_order_csv = new ExportOrderCSVServer(); |
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 | |
define( 'WP_USE_THEMES', false ); | |
require_once( './wp-load.php' ); | |
$order_id = 81; | |
$order = wc_get_order( $order_id ); | |
if ( $order ) { | |
$order_csv = array(); | |
// Add billing details on separate lines (each line is an array [within an array]). | |
$order_csv[] = array( $order->get_billing_first_name(), $order->get_billing_last_name() ); | |
$line = $order->get_billing_company(); | |
if ( ! empty( $line ) ) { | |
$order_csv[] = array( $line ); | |
} | |
$order_csv[] = array( $order->get_billing_address_1() ); | |
$line = $order->get_billing_address_2(); | |
if ( ! empty( $line ) ) { | |
$order_csv[] = array( $line ); | |
} | |
$order_csv[] = array( $order->get_billing_city() ); | |
// Get full state name instead of abbreviation. | |
$order_csv[] = array( WC()->countries->states[ $order->get_billing_country() ][ $order->get_billing_state() ] ); | |
$order_csv[] = array( $order->get_billing_postcode() ); | |
// Get full country name instead of abbreviation. | |
$order_csv[] = array( WC()->countries->countries[ $order->get_billing_country() ] ); | |
$order_csv[] = array( $order->get_billing_email() ); | |
$order_csv[] = array( $order->get_billing_phone() ); | |
$order_csv[] = array(); // Add empty line before the items. | |
// Add product name and quantity on same line (stored as an array). | |
foreach ( $order->get_items() as $item_id => $item ) { | |
//$product_id = $item->get_product_id(); | |
//$variation_id = $item->get_variation_id(); | |
//$product = $item->get_product(); // see link above to get $product info | |
$product_name = $item->get_name(); | |
$quantity = $item->get_quantity(); | |
//$subtotal = $item->get_subtotal(); | |
//$total = $item->get_total(); | |
//$tax = $item->get_subtotal_tax(); | |
//$tax_class = $item->get_tax_class(); | |
//$tax_status = $item->get_tax_status(); | |
//$allmeta = $item->get_meta_data(); | |
//$somemeta = $item->get_meta( '_whatever', true ); | |
//$item_type = $item->get_type(); // e.g. "line_item", "fee" | |
$order_csv[] = array( $product_name, $quantity ); | |
} | |
echo '<p>This is the CSV that will be generated (items with spaces are wrapped in quotes):'; | |
echo '<pre>'; | |
$out = fopen( 'php://output', 'w' ); | |
foreach ( $order_csv as $line ) { | |
fputcsv( $out, $line ); | |
} | |
fclose( $out ); | |
echo '</pre>'; | |
} | |
else { | |
echo '<p>Error: Invalid order ID.</p>'; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment