The Problem
While working on my JavaScript for WordPress redesign I came across a problem that ultimately had a simple solution, but it took me a while to figure out how to implement it.
During the checkout process in WooCommerce I have removed many of the default fields to make sign up faster. Since my course is digital I don’t ask for shipping details and the only billing details I ask for is the country and the VAT Code (using this plugin) along with email and password, which is necessary for access to courses.

The problem with this is that when people want to download an invoice it will not have some of the information they may need.
I thought that if a user was able to update their address in their My Account area then the order billing details would also be updated as well. This is not the case.
Billing (and shipping) details are stored in the post meta for WooCommerce orders. This means that we have to hook in when a user saves their address and update the post meta for all of their orders as well.
The Solution
First I want to say that this is a solution / hack for a very specific problem I have and it is not without consequences. This solution will update all orders for a custom whenever their save their billing details. I am fine with this, but your user may not expect this so proceed if this trade off is acceptable for you.
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 | |
add_action( 'woocommerce_customer_save_address', 'jsforwp_update_address_for_orders', 10, 2 ); | |
function jsforwp_update_address_for_orders( $user_id ) { | |
$customer_meta = get_user_meta( $user_id ); | |
$customer_orders = get_posts( array( | |
'numberposts' => –1, | |
'meta_key' => '_customer_user', | |
'meta_value' => $user_id, | |
'post_type' => wc_get_order_types(), | |
'post_status' => array_keys( wc_get_order_statuses() ) | |
) ); | |
foreach( $customer_orders as $order ) { | |
update_post_meta( $order->ID, '_billing_first_name', $customer_meta['billing_first_name'][0] ); | |
update_post_meta( $order->ID, '_billing_last_name', $customer_meta['billing_last_name'][0] ); | |
update_post_meta( $order->ID, '_billing_company', $customer_meta['billing_company'][0] ); | |
update_post_meta( $order->ID, '_billing_address_1', $customer_meta['billing_address_1'][0] ); | |
update_post_meta( $order->ID, '_billing_address_2', $customer_meta['billing_address_2'][0] ); | |
update_post_meta( $order->ID, '_billing_city', $customer_meta['billing_city'][0] ); | |
update_post_meta( $order->ID, '_billing_state', $customer_meta['billing_state'][0] ); | |
update_post_meta( $order->ID, '_billing_postcode', $customer_meta['billing_postcode'][0] ); | |
update_post_meta( $order->ID, '_billing_country', $customer_meta['billing_country'][0] ); | |
update_post_meta( $order->ID, '_billing_email', $customer_meta['billing_email'][0] ); | |
update_post_meta( $order->ID, '_billing_phone', $customer_meta['billing_phone'][0] ); | |
} | |
}; | |
?> |
Here is what this code does:
- Hooks into the woocommerce_customer_save_address action hook.
- woocommerce_customer_save_address gives us access to customer user ID
- Then we get the meta data for the customer using get_user_meta(). This includes the updated billing details that were just saved.
- Following that we pull in all of the orders for that customer using get_posts()
- From there we loop through all the orders and update the order meta data to match the newly saved customer data.
I want to say again that a WooCommerce users post meta data for a reason. Just because a user updates their billing information does not mean that they want their past billing details replaced for orders already placed.
This was a bit of a quick hack and I am sure folks could make this more efficient. Please share if you have ideas or found this useful!
However, this allows me to simplify my checkout process and give customers an easy way to add whatever information they need in their invoices then download them.
This solution above worked for me:
https://github.com/woocommerce/woocommerce/commit/d570a81241f49fb79007eba78bd0ad489d0911c1#diff-afb64dfd5504bb96e9b0624922ecef4f
LikeLiked by 1 person
This is exactly what I was looking for. Thank you. I only need orders that haven’t been paid for yet to be updated so I changed
‘post_status’ => array_keys( wc_get_order_statuses() )
to
‘post_status’ => [ ‘wc-pending’ ]
Here is a list of status’ for those wondering – https://github.com/woocommerce/woocommerce/blob/master/includes/wc-order-functions.php#L93-L104
LikeLike