When a new order is created in WooCommerce, it automatically gets a numeric order ID assigned by the database. Out of the box, this ID also becomes the order number that is shown to the customer on their receipt, confirmation emails, and in their account area.
Sometimes, this simple solution works just fine, but many WooCommerce store managers may want to customize the order numbers that are shown to customers, for reasons such as:
- Avoiding giving an indication of order volume that may be shown with incremental order numbers (a customer may notice how much or little the order numbers have increased when they place a second order, which may not be desirable especially for new stores with low volume)
- Making order numbers harder to guess so they are are more secure to use as a form of proof of purchase (such as in our case, where order numbers are part of our purchase activation process)
Fortunately, thanks to the extensibility built into WordPress and WooCommerce, it’s easy to implement a more sophisticated order numbering system with just a few lines of code! Let’s drive right in…
We just need to hook two functions to make this work. First, let’s generate and save the custom order number when the order is created, in the woocommerce_new_order
hook.
To generate the order number, we need to define a set of characters to use in the order number, and randomly choose from that set up to the number of characters we want in the order number.
$chars = '123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
$charsMax = strlen($chars) - 1;
$orderNumber = '';
for ($i = 0; $i < 15; ++$i) {
$orderNumber .= $chars[random_int(0, $charsMax)];
}
You can change the $chars string and the number 15 in the for loop to change which characters can appear in the order number, and the length of the order number, respectively.
Here are a few other customizations you could make:
- If you want all your order numbers to start with a prefix, or end with a suffix, just add (concatenate) it onto the
$orderNumber
after it is populated, like so:$orderNumber = 'ABC' . $orderNumber;
or$orderNumber = $orderNumber . 'XYZ';
. - If you want to break the order number up into pieces separated by dashes, try:
$orderNumber = implode('-', str_split($orderNumber, 5));
. Change5
to the length of each part between the dashes.
Secondly, we need to make sure that this order number wasn’t used in a previous order in the past. We can do this with a simple query to the database. If your orders are stored in High Performance Order Storage (HPOS), that looks like this:
$wpdb->get_var(
$wpdb->prepare(
'SELECT 1 FROM '.$wpdb->prefix.'wc_orders_meta
WHERE meta_key="my_custom_order_number"
AND meta_value=%s',
$orderNumber
)
)
It’s a bit different for legacy order storage:
$wpdb->get_var(
$wpdb->prepare(
'SELECT 1 FROM '.$wpdb->postmeta.'
WHERE meta_key="my_custom_order_number"
AND meta_value=%s',
$orderNumber
)
)
This assumes that we are saving the custom order numbers under a meta key called my_custom_order_number. Lastly, we need to save the new order number to the order under this meta key:
$order->update_meta_data('my_custom_order_number', $orderNumber);
$order->save_meta_data();
Let’s put it all together:
add_action(
'woocommerce_new_order',
function ($orderId, $order) {
if (!$order->get_meta('my_custom_order_number')) {
global $wpdb;
$chars = '123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
$charsMax = strlen($chars) - 1;
do {
$orderNumber = '';
for ($i = 0; $i < 15; ++$i) {
$orderNumber .= $chars[random_int(0, $charsMax)];
}
} while (
$wpdb->get_var(
$wpdb->prepare(
'SELECT 1 FROM '.$wpdb->prefix.'wc_orders_meta
WHERE meta_key="my_custom_order_number"
AND meta_value=%s',
$orderNumber
)
)
// Remove the following block if all of your orders are stored in HPOS
|| $wpdb->get_var(
$wpdb->prepare(
'SELECT 1 FROM '.$wpdb->postmeta.'
WHERE meta_key="my_custom_order_number"
AND meta_value=%s',
$orderNumber
)
)
);
$order->update_meta_data('my_custom_order_number', $orderNumber);
$order->save_meta_data();
}
},
10,
2
);
The other hook we need is to load our custom order numbers and use them in place of the order IDs throughout our store. This one is really simple:
add_filter(
'woocommerce_order_number',
function($orderId, $order) {
$orderNumber = $order->get_meta('my_custom_order_number');
if ($orderNumber) {
return $orderNumber;
}
return $orderId;
},
10,
2
);
That’s it – we can now add these two hooks to a custom plugin or a snippets plugin that supports PHP code, and we’re good to go!
Bonus tip – you can include your custom order number in a reporting plugin like Export Order Items Pro by adding the my_custom_order_number
meta field to the report.