I’ve been hit once again by a bot attack.
This time, I woke up to dozens of fake orders for my best-selling free mini plugin: the WooCommerce Autocomplete Orders Mini-Plugin. All of them placed overnight, all using obviously fake email addresses, and all totally useless.
Besides clogging up my order list and analytics, these spam orders also triggered multiple admin emails and slowed down my workflow.
Free products are a great way to provide value and attract users — but they also open the door to abuse.
That’s why I decided to implement a simple solution: limit how many times each free product can be ordered per day. Once the daily limit is hit, the product becomes temporarily unavailable with a “come back tomorrow” message.
In this post (and the video below), I’ll show you exactly how I did it, with a custom snippet that targets all free products in a specific category.
Spam WooCommerce Orders
It all started here, this morning, with dozens of “Completed” order emails. I immediately knew that wasn’t normal. So many orders, in a short amount of time, all targeting the same free product, and from fake email addresses:

Existing Business Bloomer Snippet
I then remembered I shared a snippet a couple of years ago, to limit the daily sales of a given product ID:
Now, what if I tweaked that to target only free products, and only a given product category (as I know spam orders target only those)?
ChatGPT and a Couple of Prompts Later…
So I asked ChatGPT:
I have this code. Make it work for ALL free products in the "plugins" product category, and display a message to come back tomorrow once the item is available again: [pasted my snippet]
Returned code was decent enough and well written, but wasn’t for some reason doing what I asked; when looping through today’s orders, I wanted to count the number of times a GIVEN product was purchased. So I refined the code:
There is no check inside the foreach to see if it's the given product_id
ChatGPT was nice enough: “You’re absolutely right — my previous version counts all free products in the “plugins” category instead of counting per individual product. Here’s the corrected version, which tracks sales per product ID within the free products of the “plugins” category”.
Finally, I refined the code with the “.woocommerce-error” class and UL-LI structure to format the error message that displays on free products once they’ve gone over the daily limit.
Now the code was perfect (find it below).
My free product, now that I received so many spam orders, is now not purchasable again for today:

PHP Snippet: Limit Daily Orders for Free Products in WooCommerce
This PHP snippet helps WooCommerce store owners prevent spam and abuse on free products by limiting how many times a product can be ordered each day. Specifically, it targets free products within the “plugins” category and makes them temporarily unavailable after 5 daily orders.
Once the limit is reached, the product becomes non-purchasable and displays an error message asking users to come back tomorrow.
This is a lightweight, code-only solution that doesn’t require additional plugins and is ideal for stores offering free downloads that frequently attract bots or fake orders. Customize the category or limit as needed.
/**
* @snippet Limit Spam WooCommerce Orders (Free Products)
* @tutorial https://businessbloomer.com/woocommerce-customization
* @author Rodolfo Melogli, Business Bloomer
* @compatible WooCommerce 9
* @community https://businessbloomer.com/club/
*/
add_filter( 'woocommerce_is_purchasable', 'bbloomer_limit_daily_sales_free_plugins', 10000, 2 );
function bbloomer_limit_daily_sales_free_plugins( $is_purchasable, $product ) {
// Only target free products in the "plugins" category
if ( floatval( $product->get_price() ) > 0 ) return $is_purchasable;
if ( ! has_term( 'plugins', 'product_cat', $product->get_id() ) ) return $is_purchasable;
$product_id = $product->get_id();
$today = date( 'Y-m-d' );
$count = 0;
$orders = wc_get_orders([
'limit' => -1,
'date_created' => $today,
'status' => [ 'processing', 'completed' ],
'return' => 'ids',
]);
foreach ( $orders as $order_id ) {
$order = wc_get_order( $order_id );
foreach ( $order->get_items() as $item ) {
$item_product_id = $item->get_product_id();
if ( $item_product_id && $item_product_id === $product_id ) {
$count += absint( $item->get_quantity() );
}
}
}
// Limit reached: make it not purchasable
if ( $count >= 5 ) {
add_filter( 'woocommerce_get_price_html', 'bbloomer_free_plugin_sold_out_message', 9999, 2 );
return false;
}
return $is_purchasable;
}
function bbloomer_free_plugin_sold_out_message( $price_html, $product ) {
if ( floatval( $product->get_price() ) == 0 && has_term( 'plugins', 'product_cat', $product->get_id() ) ) {
return '<ul class="woocommerce-error"><li>This free plugin is out of stock for today. Please come back tomorrow!</li></ul>';
}
return $price_html;
}








