WooCommerce Customer / Order / Coupon Export developer documentation

You are here:
  • KB Home
  • WooCommerce Customer / Order / Coupon Export developer documentation

Overview

This extension was designed to be as flexible as possible. To that end, filters are used to allow you to customize the generated output or replace it entirely.

When exporting as a CSV, we do have one major recommendation: We strongly recommend that you do not rely on the column ordering for the generated file. While we do our best to not change column ordering for default formats, sometimes we must do so and this will break any integrations that rely on a specific order. Instead, use the column names / keys, which are guaranteed to never change.

If you need help changing this code or extending it, we recommend getting in touch with a Woo Expert or a developer at Codeable.

 

Customization Best Practices

While you can use the filters / actions referenced in this document for doing basic customizations within your theme’s functions.php file, we strongly recommend creating a custom plugin so that if you switch themes you don’t lose your customizations.

For more information on creating a custom plugin for your WooCommerce store, read this article.

We also have several snippet examples available for reference that show you several filters in action.

 

File Name / Format Filters

 

File Name

apply_filters( 'wc_customer_order_export_{$output_type}_filename', $post_replace_filename, $pre_replace_filename, $ids );

Use this filter to change the generated file name for the specified $output_type which can be ‘csv’ or ‘xml’.

apply_filters( 'wc_customer_order_export_filename', $post_replace_filename, $pre_replace_filename, $ids );

Use this filter to change the generated file name for all output types.

Both these filters affect the file name for both downloads and uploads, but not HTTP POST (which has no file name). Here’s some sample code for changing the date/time format of the %%timestamp%% variable:

<?php // only copy this line if needed
/**
 * Change the date format for the filename from YYYY_MM_DD_HH_SS to YYYY-MM-DD
 *
 * @param string $post_replace_filename the filename after variables have been replaced
 * @param string $pre_replace_filename the filename before variables have been replaced
 * @return string the updated filename with replace variables
 */
function sv_wc_csv_export_edit_filename( $post_replace_filename, $pre_replace_filename ) {

        // define your variables here - they can be entered in the WooCommerce > Manual Export tab
        $variables = array( '%%timestamp%%' );

        // define the replacement for each of the variables in the same order
        $replacement = array( date( 'Y-m-d' ) );

        // return the filename with the variables replaced
        return str_replace( $variables, $replacement, $pre_replace_filename );
}
add_filter( 'wc_customer_order_export_filename', 'sv_wc_csv_export_edit_filename', 10, 2 );

 

Here’s some sample code for adding a %%order_numbers%% filename variable so the order numbers support Sequential Order Numbers:

<?php // only copy if needed
/**
 * Adds an %%order_numbers%% merge tag for XML Export - order export file names
 *
 * REQUIRES v2.0+ or newer of XML Export
 *
 * @param array $variables the possible merge tag variables
 * @param array $ids the IDs (order or customer) in the export file
 * @param string $export_type the export type, either 'orders' or 'customers'
 * @return array - updated list of variables / merge tags
 */
function sv_wc_xml_export_filename_order_numbers( $variables, $ids, $export_type ) {

        // only add this merge tag for orders
        if ( 'orders' !== $export_type ) {
                return $variables;
        }

        $order_numbers = array();

        // get an array of order numbers based on our IDs
        foreach ( $ids as $id ) {

                $order           = wc_get_order( $id );
                $order_numbers[] = $order->get_order_number();
        }

        $variables['%%order_numbers%%'] = implode( '-', $order_numbers );
        return $variables;
}
add_filter( 'wc_customer_order_export_xml_filename_variables', 'sv_wc_xml_export_filename_order_numbers', 10, 3 );

 

You can also add merge variables for the file name.

apply_filters( "wc_customer_order_export_{$output_type}_filename_variables", $variables, $ids, $export_type );

Use this filter to add variables into the array of accepted merge tag variables for the specified $output_type.

apply_filters( "wc_customer_order_export_filename_variables", $variables, $ids, $export_type );

Use this filter to add variables into the array of accepted merge tag variables for all output types.

 

Output Formats

Both output types have a filterable format definition that allows modifying the structure of the export. The format of the CSV will depend on an array of column headers, the resulting data array will then use this to populate each row of the CSV file. The format of the XML can be adjusted, or completely changed, to generate an entirely different kind of file.

apply_filters( 'wc_customer_order_export_format_definition', $definition, $export_type, $format, $output_type );

Use this filter to change the format definitions.

For example, if your XML requires special character support and you need to change the character encoding. See this example snippet as a starting point.

 

CSV Order Output

The CSV output also has specific filters to allow for changing the general format of the CSV file.

 

CSV Delimiter

apply_filters( 'wc_customer_order_export_csv_delimiter', ',', $this );

Use this filter to change the CSV delimiter. This is a comma (,) by default.

 

CSV Enclosure

apply_filters( 'wc_customer_order_export_csv_enclosure', '"', $this );

Use this filter to change the CSV enclosure. This is a double-quote (") by default.

 

Enabling BOM (byte-order mark)

apply_filters( 'wc_customer_order_export_csv_enable_bom', false, $this );

Use this filter to add a BOM at the start of every generated CSV file. This is disabled by default.

Here’s some example code:

<?php // only copy this line if needed
/**
 * Step 1. Add `example` column header and remove the `billing_company` column
 *
 * @param array $column_headers the original column headers
 * @param \CSV_Export_Generator $csv_generator the generator instance
 * @return array the updated column headers
 */
function sv_wc_csv_export_modify_column_headers_example( $column_headers, $csv_generator ) {

        // add the new `example` column header
        $column_headers['example'] = 'example';

        // example of removing a column from the export (e.g. the `billing_company` column)
        unset( $column_headers['billing_company'] );

        return $column_headers;
}
add_filter( 'wc_customer_order_export_csv_order_headers', 'sv_wc_csv_export_modify_column_headers_example', 10, 2 );
/**
 * Step 2. Add `example` column data
 *
 * @param array $order_data the original column data
 * @param \WC_Order $order the order object
 * @param \CSV_Export_Generator $csv_generator the generator instance
 * @return array the updated column data
 */
function sv_wc_csv_export_modify_row_data_example( $order_data, $order, $csv_generator ) {

        // Example showing how to extract order metadata into it's own column
        $meta_key_example = is_callable( array( $order, 'get_meta' ) ) ? $order->get_meta( 'meta_key_example' ) : $order->meta_key_example;

        $custom_data = array(
                'example' => $meta_key_example,
        );

        return sv_wc_csv_export_add_custom_order_data( $order_data, $custom_data, $csv_generator );
}
add_filter( 'wc_customer_order_export_csv_order_row', 'sv_wc_csv_export_modify_row_data_example', 10, 3 );
if ( ! function_exists( 'sv_wc_csv_export_add_custom_order_data' ) ) :
/**
 * Helper function to add custom order data to CSV Export order data
 *
 * @param array $order_data the original column data that may be in One Row per Item format
 * @param array $custom_data the custom column data being merged into the column data
 * @param \CSV_Export_Generator $csv_generator the generator instance
 * @return array the updated column data
 */
function sv_wc_csv_export_add_custom_order_data( $order_data, $custom_data, $csv_generator ) {

        $new_order_data   = array();

        if ( sv_wc_csv_export_is_one_row( $csv_generator ) ) {

                foreach ( $order_data as $data ) {
                        $new_order_data[] = array_merge( (array) $data, $custom_data );
                }

        } else {
                $new_order_data = array_merge( $order_data, $custom_data );
        }

        return $new_order_data;
}

endif;
if ( ! function_exists( 'sv_wc_csv_export_is_one_row' ) ) :
/**
 * Helper function to check the export format
 *
 * @param \CSV_Export_Generator $csv_generator the generator instance
 * @return bool - true if this is a one row per item format
 */
function sv_wc_csv_export_is_one_row( $csv_generator ) {

        $one_row_per_item = false;

        if ( version_compare( wc_customer_order_csv_export()->get_version(), '4.0.0', '<' ) ) {

                // pre 4.0 compatibility
                $one_row_per_item = ( 'default_one_row_per_item' === $csv_generator->order_format || 'legacy_one_row_per_item' === $csv_generator->order_format );

        } elseif ( isset( $csv_generator->format_definition ) ) {

                // post 4.0 (requires 4.0.3+)
                $one_row_per_item = 'item' === $csv_generator->format_definition['row_type'];
        }

        return $one_row_per_item;
}

endif;

 

 

XML Order Output

The XML output also has specific filters to allow for changing the general format of the XML file.

 

XML Version

apply_filters( 'wc_customer_order_export_xml_version', $xml_version );

Use this filter to change the XML version specified in the generated XML. This is 1.0 by default.

 

XML Encoding

apply_filters( 'wc_customer_order_export_xml_encoding', $xml_encoding );

Use this filter to change the XML encoding specified in the generated XML. This is UTF-8 by default. Here’s some sample code for changing to ISO-8859-1:

function wc_sample_xml_change_xml_encoding() {
    return 'ISO-8859-1';
}
add_filter( 'wc_customer_order_xml_export_suite_xml_encoding', 'wc_sample_xml_change_xml_encoding' );

 

Customizing Customer Output

The output of the export can be customized easily using the built-in custom format builder (version 4.0+). However, you may want to conditionally change a default format, for which the built-in filters are helpful. For instance, you can add columns in a particular location or to add additional information. View this code snippet to add both username and customer role in the exported CSV in particular locations.

 

Adjust Included Customers

By default, all non-employee purchasers are included in the customer export (if using WordPress 4.4+) — administrators and shop managers are excluded from the customer export. However, you could customize this to only include certain roles.

apply_filters( 'wc_customer_order_export_{$output_type}_user_query_args', $query_args );

Where $output_type refers to either ‘csv’ or ‘xml’.

apply_filters( 'wc_customer_order_export_user_query_args', $query_args, $output_type );

Use this to adjust the query regardless of output type.

 

Here’s an example to limit the customer CSV export to certain roles.

 

Adding Extra Customer Data

You can add customer data to the exported customer file, so long as this data is part of the WooCommerce customer data or accessible as part of the WP User object.

 

CSV Customer Output

You’d use the wc_customer_order_export_csv_customer_headers filter to add the column header / name, and the wc_customer_order_export_csv_customer_row to populate the data for that column. Here’s an example snippet for adding customer columns to your CSV.

 

XML Customer Output

You’d use the wc_customer_order_export_xml_customers_xml_data filter to add the tag / value before the XML is generated, and wc_customer_order_export_xml_customers_xml to edit the XML directly.

 

Rename, Re-order, or Remove Customer Data

You can customize what data is included and the respective order in the exported file. You can also remove unnecessary data. Here are some examples that can be used to remove, rename, or re-order customer export data:

 

Modifying CSV Output

  • Re-order columns
  • Remove export column
  • Rename column

 

Modifying XML Output

  • Re-order tags
  • Remove export tags
  • Rename tag

 

Customizing Order Output

The output of the order file can be customized easily using the built-in custom format builder (version 4.0+). However, you may want to conditionally change a default format, for which the built-in filters are helpful.

 

Adjust Included Orders

All orders will be included in your export, or the export query can be adjusted based on order status, products in the order, categories in the order, or the order date. If you need to make further adjustments to the orders included in the export, the query arguments can be filtered further:

apply_filters( 'wc_customer_order_export_{$output_type}_query_args', $query_args, $export_type, $output_type );

Where $output_type refers to either ‘csv’ or ‘xml’.

apply_filters( 'wc_customer_order_export_query_args', $query_args, $export_type, $output_type );

Use this to adjust the query regardless of output type.

Be sure to check that 'orders' === $export_type if scoping your code to order exports.

 

Here’s an example to limit order exports to only orders that have at least one refund associated with them.

 

Adding Extra Order Data

Due to the differences of output formats between XML and CSV, you will need to use different filters, depending on which output type you want to export.

 

Adding CSV Output

If you need to add additional columns to the order CSV export, you’ll use two filters — one to add the column headers and another to set the data for the columns for each row. Here’s a structural sample:

<?php // only copy this line if needed
/**
 * Step 1. Add `example` column header and remove the `billing_company` column
 *
 * @param array $column_headers the original column headers
 * @param \CSV_Export_Generator $csv_generator the generator instance
 * @return array the updated column headers
 */
function sv_wc_csv_export_modify_column_headers_example( $column_headers, $csv_generator ) {

        // add the new `example` column header
        $column_headers['example'] = 'example';

        // example of removing a column from the export (e.g. the `billing_company` column)
        unset( $column_headers['billing_company'] );

        return $column_headers;
}
add_filter( 'wc_customer_order_export_csv_order_headers', 'sv_wc_csv_export_modify_column_headers_example', 10, 2 );
/**
 * Step 2. Add `example` column data
 *
 * @param array $order_data the original column data
 * @param \WC_Order $order the order object
 * @param \CSV_Export_Generator $csv_generator the generator instance
 * @return array the updated column data
 */
function sv_wc_csv_export_modify_row_data_example( $order_data, $order, $csv_generator ) {

        // Example showing how to extract order metadata into it's own column
        $meta_key_example = is_callable( array( $order, 'get_meta' ) ) ? $order->get_meta( 'meta_key_example' ) : $order->meta_key_example;

        $custom_data = array(
                'example' => $meta_key_example,
        );

        return sv_wc_csv_export_add_custom_order_data( $order_data, $custom_data, $csv_generator );
}
add_filter( 'wc_customer_order_export_csv_order_row', 'sv_wc_csv_export_modify_row_data_example', 10, 3 );
if ( ! function_exists( 'sv_wc_csv_export_add_custom_order_data' ) ) :
/**
 * Helper function to add custom order data to CSV Export order data
 *
 * @param array $order_data the original column data that may be in One Row per Item format
 * @param array $custom_data the custom column data being merged into the column data
 * @param \CSV_Export_Generator $csv_generator the generator instance
 * @return array the updated column data
 */
function sv_wc_csv_export_add_custom_order_data( $order_data, $custom_data, $csv_generator ) {

        $new_order_data   = array();

        if ( sv_wc_csv_export_is_one_row( $csv_generator ) ) {

                foreach ( $order_data as $data ) {
                        $new_order_data[] = array_merge( (array) $data, $custom_data );
                }

        } else {
                $new_order_data = array_merge( $order_data, $custom_data );
        }

        return $new_order_data;
}

endif;
if ( ! function_exists( 'sv_wc_csv_export_is_one_row' ) ) :
/**
 * Helper function to check the export format
 *
 * @param \CSV_Export_Generator $csv_generator the generator instance
 * @return bool - true if this is a one row per item format
 */
function sv_wc_csv_export_is_one_row( $csv_generator ) {

        $one_row_per_item = false;

        if ( version_compare( wc_customer_order_csv_export()->get_version(), '4.0.0', '<' ) ) {

                // pre 4.0 compatibility
                $one_row_per_item = ( 'default_one_row_per_item' === $csv_generator->order_format || 'legacy_one_row_per_item' === $csv_generator->order_format );

        } elseif ( isset( $csv_generator->format_definition ) ) {

                // post 4.0 (requires 4.0.3+)
                $one_row_per_item = 'item' === $csv_generator->format_definition['row_type'];
        }

        return $one_row_per_item;
}

endif;

 

Since custom formats were added in version 4.0+, these may have a one row per item format. If you maintain a plugin that has compatibility with this format, you’ll want a way to check if this format is in use. Here’s an example:

 

/**
 * Helper function to check the export format
 *
 * @param \WC_Customer_Order_CSV_Export_Generator $csv_generator the generator instance
 * @return bool - true if this is a one row per item format
 */
function sv_wc_csv_export_is_one_row( $csv_generator ) {

    $one_row_per_item = false;

    if ( version_compare( wc_customer_order_csv_export()->get_version(), '4.0.0', '<' ) ) {
        // pre 4.0 compatibility
        $one_row_per_item = ( 'default_one_row_per_item' === $csv_generator->order_format || 'legacy_one_row_per_item' === $csv_generator->order_format );
    } elseif ( isset( $csv_generator->format_definition ) ) {
        // post 4.0 (4.0.3+)
        $one_row_per_item = 'item' === $csv_generator->format_definition['row_type'];
    }

    return $one_row_per_item;
}

You can then use this check within your plugin or custom code to ensure you’ve added your custom data correctly:

if ( sv_wc_csv_export_is_one_row( $csv_generator ) ) {
        foreach ( $order_data as $data ) {
                $new_order_data[] = array_merge( (array) $data, $custom_data );
        }
} else {
        $new_order_data = array_merge( $order_data, $custom_data );
}

However, this would only apply if you already have access to the CSV_Export_Generator instance in your filter / code. If for some reason you need to check the row type for a custom format outside of a filter that gives you access to this, you can check the format definition this way:

$format_definition = wc_customer_order_csv_export()->get_formats_instance()->get_format( 'orders', 'custom', 'csv' );

The $format_definition['row_type'] will be ‘item’ or ‘order’ for the custom format, letting you then act on the format from there. You may also want to use this for retrieving XML formats, by switching the output type to ‘xml’ instead.

 

Here are some more example scripts for adding additional data to the CSV order export:

  • You can show the item price in the Default export formats with this code snippet.
  • You can add the product and variation IDs (if the product is variable) to the Default export formats with this code snippet.

 

Adding XML Output

The root element is taken from the export type by default, in this case, Orders. To adjust this you will need to use the following filter:

apply_filters( 'wc_customer_order_export_xml_root_element', ucfirst( $export_type ), $this );

where $this corresponds to the XML/CSV Generator instance.

If you need to add extra data directly to your XML order export, then you’ll need to use the following:

apply_filters( 'wc_customer_order_export_xml_get_orders_xml_data', array( 'Order' => $orders ), $orders );

This defines the data used for the Orders tag, by default this will be an array of Order tags and the individual XML for each order.

 

To add the extra data to the XML before it is generated, you’ll need to use:

apply_filters( 'wc_customer_order_export_xml_order_data', array(
    'OrderId'            => $order->id,
    'OrderNumber'        => $order->get_order_number(),
    // ...etc
), $order );

This defines the format for each individual order element and passes in an WC_Order order object for each order being exported.

If you’d like to have more fine grained control over the exported data, it is also possible to adjust line_items, shipping_items, fee_items, and tax_items separately too. As an example, to add data to an Order’s LineItems, the following filter can be used:

 

apply_filters( 'wc_customer_order_xml_export_suite_order_line_item', array(
    'SKU'       => $product->get_sku(),
    'Quantity'  => $item['qty'],
    'Price'     => $product->get_price(),
    'LineTotal' => $item['line_total'],
    'Meta'      => $item_meta
), $order, $item );

This defines the format for each individual line item within an order, and passes in the WC_Order order object for the line item’s order, and the $item array which contains the information about the line item.

The following filters can be used with a similar approach:

  • wc_customer_order_export_xml_order_shipping_item
  • wc_customer_order_export_xml_order_fee_item
  • wc_customer_order_export_xml_order_tax_item

 

It’s also possible to adjust the OrderNote format too:

apply_filters( 'wc_customer_order_export_xml_order_note', array(
    'Date'    => $note->comment_date,
    'Author'  => $note->comment_author,
    'Content' => str_replace( array( "\r", "\n" ), ' ', $note->comment_content ),
), $note, $order );

This defines the format for each order note within an order, and passes in the $note object, which contains order note comment object, along with the WC_Order order object for the order.

 

Here are some more example scripts for adding additional data to the XML order export:

  • Here’s an example of adding Product Add-ons in a nested format to the LineItems tag.
  • You can view this example snippet to add VAT Numbers per order.

 

Rename, Re-order, or Remove Order Data

 

Adjusting CSV Output

You can rename or reorder the columns using this filter:

apply_filters( 'wc_customer_order_export_csv_order_headers', $column_headers, $generator );

If you’d like to remove the CSV headers from the export entirely, however, you’ll need to remove the filter function that generates this for the output. There is an example snippet to remove the headers in our snippet repository.

 

Occasionally you might need to change the CSV after it’s already been generated though. To do this, you can use the following filter for each $export_type:

apply_filters( 'wc_customer_order_export_get_${export_type}_csv_output', $csv, $order_data, $ids, $export_format, $custom_export_format );

where the export type can be: ‘orders’, ‘customers’, or ‘coupons’.

 

When using the default format, you can add / remove / modify line item entries using the filter:

apply_filters( 'wc_customer_order_csv_export_order_line_item', $line_item, $item );

This passes in the existing line item entries along with the WC Order Item array.

Here’s some sample code for adding the product’s weight as item meta in the CSV export.

If you wanted to modify existing data, you can do so for the line items and columns using the column header keys. Here’s a working example that will change all prices from machine-readable values to localized price output for currency.

 

It’s also possible to separate data into multiple columns. For example, the ‘coupons’ column contains all coupon data, but this data could be expanded into individual columns with the Default formats. This sample code snippet will separate the ‘coupons’ column into 3 columns per coupon used: 'coupon_{$count}_name''coupon_{$count}_description', and 'coupon_{$count}_amount'.

 

Here’s a collection of some additional samples:

  • Re-order columns
  • Remove columns
  • Rename columns

 

Adjusting XML Output

The XML is generated from an Array of XML tags, so you can adjust the order or remove tags by using this filter:

apply_filters( 'wc_customer_order_export_xml_order_data', array(
    'OrderId'            => $order->id,
    'OrderNumber'        => $order->get_order_number(),
    // ...etc
), $order );

 

Updating order status after export

You can update an order’s status after export by using the:

apply_filters( 'wc_customer_order_export_mark_order_exported', $mark_order_as_exported, $order, $method, $handler )

or by hooking into the wc_customer_order_export_{$output_type}_order_exported action.

Here are a couple examples of updating the status on every export, or only for paid orders. $output_type in this case can be either ‘csv’ or ‘xml’.

 

Additional Filters

 

HTTP POST Filters

If you’re using the automatic export over HTTP POST, there is a filter available to change the arguments used for wp_remote_post().

apply_filters( 'wc_customer_order_export_http_post_args', [
    'timeout'     => 60,
    'redirection' => 0,
    'httpversion' => '1.0',
    'sslverify'   => true,
    'blocking'    => true,
    'headers'     => [
        'accept'       => $content_type,
        'content-type' => $content_type,
    ],
    'body'        => $contents,
    'cookies'     => [],
    'user-agent'  => "WordPress " . $GLOBALS['wp_version'],
] );

For example, if the web service you’re posting to requires authentication, you could use this filter to add HTTP basic auth to the headers:

 

function wc_csv_export_add_http_post_basic_auth( $args ) {
    // you can set other HTTP headers using the format $args['headers']['Header Name'] = 'header value'
    $args['headers']['Authorization'] = 'Basic ' . base64_encode( 'your_username:your_password' );

    return $args;
}
add_filter( 'wc_customer_order_csv_export_http_post_args', 'wc_csv_export_add_http_post_basic_auth' );

 

Admin Filters

If you’d like to customize the query arguments that are used for selecting orders to export on the Export > Manual Export screen, use:

apply_filters( 'wc_customer_order_export_query_args', $query_args, $export_type, $output_type );

You can also customize query arguments used for the customer export using:

apply_filters( 'wc_customer_order_export_user_query_args', $query_args, $output_type )


Here’s an example that lets you determine which user roles are included as customers in the export.

 

Custom Data Stores

From v4.5.0 of the plugin, it is now possible to imnplement a custom data store. As standard, we include a database store which will stream the export results where possible, rather than processing and sending the whole file at once. This increases server efficiency, especially when downloading very large exports.

Database streaming does require the MySQLi extension to be enabled, and used, by WordPress. In some cases, MySQLi will be installed on the server but not put to use by WordPress. This can be remedied by adding define( 'WP_USE_EXT_MYSQL', false ); to the WordPress config file.

Here are just a few examples of things that would be possible with custom data stores:

  • Store exports in a separate MySQL database from the main WordPress instance.
  • Store exports in a completely different database engine such as PostgresSQL or MongoDB.
  • Store exports off-site, on a separate server, or with a storage service such as Amazon S3.
  • Perform transformations on the data as it is being stored/retrieved — i.e. file compression, or encryption.

To get started, you will need to implement the abstract WC_Customer_Order_CSV_Export_Data_Store and hook into the filter:

$data_store = apply_filters( "wc_customer_order_export_{$output_type}_custom_data_store", $type );

where $output_type will be either ‘csv’ or ‘xml’. You may also want to look at our included WC_Customer_Order_CSV_Export_Data_Store_Database class for further information.

Was this article helpful?
Dislike 0
Views: 0

Cart

Log in

Create an Account
Back to Top