Skip to content

Instantly share code, notes, and snippets.

@damiencarbery
Last active April 5, 2024 16:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save damiencarbery/d387d7ee2d860789030347eb68b11589 to your computer and use it in GitHub Desktop.
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.
<?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();
<?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