Too many requests : blocking access to unused Woocommerce features

This entry was posted in Blog on by .

WordPress as a Content Management System with Woocommerce to drive an online shop are two very powerful and useful tools.  We have built and run a number of Woocommerce shops, and we love the power and ease of use it offers.

However, there are some situations where there might actually be just TOO much functionality.  I came across one of these situations recently on the Shop on the Borderlands. This online shop has a very high number of unique products (thousands of them).

By default, Woocommerce creates a shortcut ‘Add to Cart’ link to every product. The advantage of this if you are selling a few simple items is that you can link direct from your blog post or email to the ‘add to cart’ functionality and allow people to buy with one click.

The downsides are that if you have complex products, where you want people to read the full product description, you never want them to do that.   And, because the system is automatically creating a unique ‘add to cart’ link for every product, if your website gets hit by some annoying piece of software that goes through making a lot of requests at once, this will put the all-important site database under a lot of strain.

Add to Cart links can’t be cached, or protected using services like Cloudflare: every Add to Cart action makes the website database do work.  And if you have thousands of products, a program that automatically hits all the ‘add to cart’ links in a couple of seconds can quickly slow the site to a crawl.   No human user will do this.  A human user will hit one product button and make a form request.  Only automated software follows hundreds of links simultaneously.

The answer is to remove all the ‘Add to Cart’ links, and then use the site’s .htaccess file from allowing anyone to access the paths.  You don’t even want those paths to return a ‘404 not found, because even a 404 could put some load on the database, and there’s no reason for those requests to hit the database at all, and slow things down for your all-important real human customers.

OK.  Before I give the code, here’s the obligatory warning.  Before you change your site’s functions.php file or .htaccess file, take a backup copy of the working version. You know that, right?

Here’s the code I added to my theme’s functions.php file to get rid of the visible buttons in Woocommerce that point to the Add to Cart links.  (note that this won’t remove the all important ‘add to cart’ message on the actual product page!  That’s implemented as a form, not a link, so you don’t have to worry about it.)

// hide the 'add to cart' button on category pages.
add_action('wp', 'hideaddtocart');
function hideaddtocart(){
if (is_archive()) {
// make all items unpurchasable if it's a category
add_filter( 'woocommerce_is_purchasable', '__return_false');
} 
}

// hide the 'read more' link that appears on unpurchasable items.

if (!function_exists('woocommerce_template_loop_add_to_cart')) {
function woocommerce_template_loop_add_to_cart() {
global $product;
if ( ! $product->is_in_stock() || ! $product->is_purchasable() ) return;
wc_get_template('loop/add-to-cart.php');
}
}


// removes the add to cart on 'related products'

add_filter( 'woocommerce_loop_add_to_cart_link', 'replacing_add_to_cart_button', 10, 2 );
function replacing_add_to_cart_button( $button, $product ) {
// nothing goes here since we don't actually want a button.
}

OK! so now we can only Add to Cart from the product page, where customers can read all the necessary description, and we no longer have a huge list of ‘add to cart’ links that annoying bots can follow to slow your site down and use up all your site memory.

But if the site has previously been spidered, or if the bot software is particularly annoying, they’ve probably already got a record of where the ‘Add to Cart’ urls were.  So my next step was to edit the site .htaccess file to stop anyone accessing those links at all.

I added this:

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteCond %{THE_REQUEST} /cat/[^?]*\?add-to-cart=\d+ [NC]
RewriteRule ^ - [F]
RewriteCond %{REQUEST_METHOD} !POST
RewriteCond %{THE_REQUEST} /product/[^?]*\?add-to-cart=\d+ [NC]
RewriteRule ^ - [F]
</IfModule>

The unusual lines are the RewriteCond ones: these give the pattern to match for the two URLs created by  Woocommerce for ‘add to cart’ links.
And then after that, the rewriteRule says: if this rule is matched, FAIL.  IE, do nothing.  Don’t load the page, don’t access the database, just give an error.  No human will be following those links, you don’t need to give a friendly message.  Just fail.

I did this and the site speed roughly trebled and the annoying out of memory errors went away.  What a relief.