SkyVerge WooCommerce Extensions

A popular feature with WooCommerce Memberships is the ability to import and export members. While the default export includes membership data, you may want to include other data here as well. Modifying the export is possible, as there are hooks available to change the CSV output; we’ll go over a couple straight-forward examples in this guide.

Please note this guide requires beginner PHP development and WordPress skills.

Filter WooCommerce Memberships Export Column Headers

The first step in adjusting the member export is the ability to filter the column headers. This makes it possible to add, remove, or re-order columns in the export. This hook is available to modify headers:

apply_filters( 'wc_memberships_csv_export_user_memberships_headers', $headers, $export_instance );

Example 1: Remove unneeded headers

Let’s say you want to remove the membership plan ID and “has_access” columns. Doing so is simple, as you just need to remove the headers for these columns, and they won’t be output.

function sv_wc_memberships_modify_member_export_headers( $headers ) {

    // remove any unwanted headers
    unset( $headers['membership_plan_id'], $headers['has_access'] );
    return $headers;
add_filter( 'wc_memberships_csv_export_user_memberships_headers', 'sv_wc_memberships_modify_member_export_headers' );

That’s all it takes!

Example 2: Adding new headers

Adding headers is straight-forward as well:

function sv_wc_memberships_modify_member_export_headers( $headers ) {

    $headers['member_phone'] = 'member_phone';
    return $headers;
add_filter( 'wc_memberships_csv_export_user_memberships_headers', 'sv_wc_memberships_modify_member_export_headers' );

However, if you’re going to add a new header, you must also populate it with content.

Filter WooCommerce Memberships Export Column Content

If you want to add new columns to the file, you must also filter the column cell to populate it with the data for each member. We can do so with this hook:

apply_filters( "wc_memberships_csv_export_user_memberships_{$column_name}_column", '', $column_name, $user_membership, $export_instance );

This lets you adjust the data for that column. Notice that the filter name is dynamic — the $column_name will be replaced with the header name you’ve added. The $user_membership parameter is included and will let you get the user data you need.

For example, the user ID can be obtained with: $user_membership->get_user_id(), which can let you get the WP User data.

Let’s take our member_phone example above — we can now populate this cell using the wc_memberships_csv_export_user_memberships_member_phone_column filter (I’ve replaced the column name variable with the key I previously set).

function sv_wc_memberships_modify_member_export_columns( $data, $_, $user_membership ) {
    // return the data for this column
    return get_user_meta( $user_membership->get_user_id(), 'billing_phone', true );
add_filter( 'wc_memberships_csv_export_user_memberships_member_phone_column', 'sv_wc_memberships_modify_member_export_columns', 10, 3 );

Notice that I don’t have to scope this data to a particular column, as the filter name does that for me, so I can just return the data I need for the new column.

Adjust WooCommerce Memberships Exports: Putting it Together

Adding columns and removing them is pretty simple, so let’s put these together with a snippet that (1) removes some unwanted columns, (2) adds a new column in a specific position, and (3) adds the data for the new column.

My export will start off like this:

WooCommerce Memberships Export: original data

We’ll remove a couple of columns, and insert the column for the member’s phone number (view snippet here):

 * Modify the member CSV Export column headers.
 * @param string[] $headers array of column headers as 'key' => 'output_name'
 * @return string[] updated headers
function sv_wc_memberships_modify_member_export_headers( $headers ) {

    // remove any unwanted headers
    unset( $headers['membership_plan_id'], $headers['has_access'] );

    $new_headers = array();

    // add a column header for "member phone"
    foreach ( $headers as $key => $name ) {

        $new_headers[ $key ] = $name;

        // add our new header after the member email
        if ( 'member_email' == $key ) {
            $new_headers['member_phone'] = 'member_phone';
    return $new_headers;
add_filter( 'wc_memberships_csv_export_user_memberships_headers', 'sv_wc_memberships_modify_member_export_headers' );

 * Adds data for our new member export column.
 * Note that no column name check is needed since the filter name is scoped to the column key.
 * @param string[] $data export data as 'column' => 'data'
 * @param string $_ unused, the column key
 * @param \WC_Memberships_User_Membership $user_membership User Membership object
 * @return string[] updated data
function sv_wc_memberships_modify_member_export_columns( $data, $_, $user_membership ) {
    // return the data for this column
    return get_user_meta( $user_membership->get_user_id(), 'billing_phone', true );
add_filter( 'wc_memberships_csv_export_user_memberships_member_phone_column', 'sv_wc_memberships_modify_member_export_columns', 10, 3 );

Now some columns have been removed, and our new column is added after the “member email” column:

WooCommerce Memberships Export: modified data

This can allow you to add further user data, membership data, or plan data to member export files.

Published by Beka Rice

Beka leads product direction for SkyVerge and technical documentation. She spends a lot of time on research and interviews, but likes to write so she has an excuse to spend more time jamming out to anything from The Clash to Lady Gaga.


  1. Hello Beka,

    Thank you for the useful tutorial on adding extra columns to the export. I just have a couple of queries which hopefully you can help me out with:

    How do you export Notes from a user? and import notes aswell?
    Is it possible to apply a similar logic to your tutorial to import users along with billing info etc?

    • (1) as notes are comments, that data isn’t stored on the user membership itself, so you’d need to query the comments table to get them and put them in a column. Not impossible, but definitely more involved. Same goes for imports, except you’d need to parse the notes / comments column and create comments upon import.
      (2) User data could be set on import — here’s a basic example of the two steps: (a) prepare the imported data, potentially setting any defaults, (b) use the import data to modify the user membership. In your case, you’d need to modify the user instead to add a phone number, not the user membership, so you’d need to work backwards with $user_membership->get_user_id(). Not something I have an example for, but not too crazy to do 🙂

      • That is great Beka, thank you for your reply. I’ll give both those a go. Have a good one.

  2. Would you be able to show an example that adds more than one column to the export fields? I’m struggling with the syntax when the column name needs to be dynamic. My use case is that I would like to add the physical address to the export information. Thanks for the help!

    • Hey DF, to add multiple headers you’d
      (1) add additional column names by duplicating this: $new_headers['member_phone'] = 'member_phone';
      so this would become something like:
      $new_headers['column1'] = 'column_1';
      $new_headers['column2'] = 'column_2';

      (2) Then you’d duplicate the function we have that adds data for the new member export column. Since the filter name changes as outlined above, you’d add a new function for each new column + filter you’re using.

      However, likely the issue is due to this: “…when the column name needs to be dynamic”. Note that the column ID (the array key) cannot be dynamic, as that key is used to match up where the data goes, so these need to be consistent.

      • Beka,

        I followed your advice and this is what I have (snippet below) and am receiving an error “Cannot redeclare sv_wc_memberships_modify_member_export_columns() (previously declared in /wordpress/htdocs/wp-content/plugins/code-snippets/php/admin-menus/class-edit-menu.php(180) : eval()’d code:43)” — Any idea what I’m doing wrong?:

        function sv_wc_memberships_modify_member_export_columns( $data, $_, $user_membership ) {
        // return the data for this column
        return get_user_meta( $user_membership->get_user_id(), ‘billing_address_1’, true );
        add_filter( ‘wc_memberships_csv_export_user_memberships_member_address_1_column’, ‘sv_wc_memberships_modify_member_export_columns’, 10, 3 );
        //Add the Address 2 line
        function sv_wc_memberships_modify_member_export_columns( $data, $_, $user_membership ) {
        // return the data for this column
        return get_user_meta( $user_membership->get_user_id(), ‘billing_address_2’, true );
        add_filter( ‘wc_memberships_csv_export_user_memberships_member_address_2_column’, ‘sv_wc_memberships_modify_member_export_columns’, 10, 3 );

  3. Hello Beka,

    I was wondering whether you have any advise on extending the reporting side of this plugin? I’d like to add the ability to choose a custom user field and filter the users by that value. E.g. export al the members where post = true … any help in adding this would be great.

    Thank you in advanced.

    • Hey Josh! Afraid this isn’t something I’ve done so I don’t have examples handy, but my recommended approach would be to remove the row entirely if it doesn’t contain your desired data — the wc_memberships_csv_export_user_memberships_row filter should help with this.

      • Thank you Beka, that is useful. I will look into it.

        Do you have hooks to add a custom option into the export form?

        • Yep, have a look at includes/admin/class-wc-memberships-import-export-handler.php — the wc_memberships_csv_export_user_memberships_options filter lets you adjust those options to add your own.

  4. Hello. Thanks for the article it defintely set me on the right track. I seem to be having an issue though with adding the export of a user’s role. I can get it to add the column however I can’t seem to get it to populate the field. I have included below what I am trying to use to populate the field. However it seems that you can’t use a user_id to find a user’s roles but you first have to pull the user’s metadata.( Could you help me figure out how to change this so it correctly populates the field? Thanks

    unction sv_wc_memberships_modify_member_export_columns( $data, $_, $user_membership ) {
    // return the data for this column
    return get_user_meta( $user_membership->get_user_id(), 'wp_roles', true );
    add_filter( 'wc_memberships_csv_export_user_memberships_wp_roles_column', 'sv_wc_memberships_modify_member_export_columns', 10, 3 );

    • Hey Jacob — looks like you’re trying to get user meta, but there is no user meta that stores roles — as that SO article notes, you need to get the user object first, then can implode the array of roles into a list.

      • Thanks for the response. I was able to figure it out. Another question I had which I think is somewhat similar to Josh Holmes question, is there a way for me to add an export option to export members of certain roles? So not adding an additional column but only export users of a certain role, as long as they meet all the other settings such as membership type, expiration date, etc?

        • Yep, per the response to Josh, the best way to do this is to filter wc_memberships_csv_export_user_memberships_row — you could check the user role for that row / record, and remove the row if it doesn’t match. If you want to control this via an export setting, then the wc_memberships_csv_export_user_memberships_options lets you add your own options.

  5. Hello Beka!

    I have added a couple custom fields to the memberships export page using the wc_memberships_csv_export_user_memberships_options filter. But I’m not sure where to go about adding the functionality of those fields into the filter process of the export. So my setup is like this:

    (Beginning) Export Page: Added my custom fields
    (Middle) Filter memberships with custom field values: Stuck here…
    (End) Modify headers and their data: I’m good here. Have great working examples thanks to your docs!

    Could you point me in the right direction for modifying the actual filtering of the data with values from my custom fields as params?

    Thank you!!!

    • Hey Shane, the best way to do this is to filter wc_memberships_csv_export_user_memberships_row — you could check for your custom field (on the user or membership) for that row / record, and remove the row if it doesn’t match.

      • Hey Beka, could you point me to the reference file this is in? I’m not finding any documentation on this…

        • Hey Shane, it’s in: includes/utilities/class-wc-memberships-csv-export-user-memberships.php

          • Hello again Beka! I appreciate you helping point the direction on this. I’m getting close to nailing this, but am having another issue…

            I have hooked my function into wc_memberships_csv_export_user_memberships_row and I can remove rows easily here. But I have a couple problems:

            I have ( $row, $user_membership, $this, $job ) as my params, but only $row returns any data. So I can filter the rows, but $job is not sending my custom field data (or any other data.. I was thinking this passed on the POST information from the form). ** I have a feeling I’m doing something wrong here. Maybe only $row is passed instead of all 4 params. **
            Since number 1 above did not work for me, I am trying to retrieve my custom field data by $_POST[‘custom_field_name’]; but it returns null.

            So I am completely stuck on how to retrieve the entered data in the custom fields… If you could help me on this last thing, this should be all I need! 🙂

            PS. After I learn how to get the entered data in custom fields, do you think it would be more wise to update the query_args instead of filtering rows? This way it’s not having to filter every single membership and instead gets only the membership ID’s needed? I noticed this filter here: wc_memberships_csv_export_user_memberships_query_args

            Thank you again!

          • Hey Beka, I’m still struggling with this :/ Any thoughts? I really appreciate your help!

          • Hey Beka, sorry to bug you, but have you seen my comments by chance?

          • Hey Shane, I’m afraid we don’t check comments on the site regularly — the best way to get assistance for time-sensitive questions is via support.

            I’m afraid I’m not able to replicate any issues with the parameters from wc_memberships_csv_export_user_memberships_row — all are present for me while filtering the value of the row, so I’d start by deactivating other plugins and customizations. I would, however, recommend filtering the query args instead as you’ve noted if that works for your use-case.

            Finally, RE passing custom options into the job, this isn’t something I’ve done myself, so I don’t have notes handy. Could you submit a support conversation so I can loop in our development team here? thanks!

  6. Hi,
    Thanks a lot for your help.

    One more questions, please.
    How to simply rename column headers ?

    Best regards

    • Hey Sébastien, the first filter mentioned here for the file headers would let you rename them — the headers use an associative array of key => name, so you can change the name for a given key in your export file.

  7. Hey Beka, Do you know how can i import the same fields from the exported csv. Which have new headers.

    • Hey Aman, you’ll want to check out the wc_memberships_csv_import_user_memberships_data filter to “register” the new column, then the wc_memberships_csv_import_user_membership action, which fires during import, to use that data if needed (e.g., updating the user or membership record).

Hmm, looks like this article is quite old! Its content may be outdated, so comments are now closed.