Woocommerce – Easy Free Downloadable Product Samples
In a hurry and know how to setup an External/Affiliate product? Use the download link at the bottom of the page to download the two files you need, and then read this.
For the new JohnVosler.com, we wanted to give away a 10-minute guided breath meditation, to give people who are unfamiliar with his Yoga Nidra CDs/MP3s an introduction. And we wanted to give it away free – free as in really free, not as in ‘give us your email address’ or ‘like us on Facebook’ and we’ll give it to you. That’s not free. And definitely not ‘go through our entire checkout process as if you’re paying for something and we’ll send you a link.’ In place of ‘Add to Cart’ we just wanted a ‘Download Now’ button.
Obviously we’ll be tracking those downloads to get an understanding of how many visitors are downloading it and from where, but if visitors want to sign up for his mailing list, the subscribe box is in the footer.
Woocommerce (we’re on 2.1.5 currently) makes it pretty straightforward to do something like this, up to a point. Create a new product, and under ‘Product Data’, select ‘External/Affiliate.’ In your product URL, enter the URL of the downloadable file. Then in your Button Text, add ‘Download Now’ (or similar).
Configure the rest of the product as you wish and save. Seems easy, right? But when you visit the frontend and click ‘Download Now,’ in most modern browsers you’ll get a player and the file will begin playing. Not downloading.
HTML5 includes a download attribute, which will force download and allows us to pass along a file name to save the file as. In order to add this attribute to our link, we’ll have to quickly modify a couple of files. If you’re not familiar with modifying Woocommerce template files, it might be worthwhile to read the official guide.
First step is to make a ‘woocommerce’ folder in your active theme folder, this is where we’ll stick the modified files so they overwrite the default Woocommerce files. Inside of that folder, we’re going to make two additional folders. One called ‘loop’ and the other called ‘single-product.’ In the single product folder, add another called ‘add-to-cart.’
As you can see, we’re going to change two files. ‘external.php’ and ‘add-to-cart.php.’ If you prefer, just use the link below to download the files and upload them to the appropriate folders – add-to-cart.php to ‘loop’, and external.php to ‘single-product’ -> ‘add-to-cart’. Otherwise, you can copy the two files from the Woocommerce plugin folder. Open that folder and in the ‘templates’ folder inside you’ll see the ‘loop’ and ‘single-product’ folders, just as we’ve created. You can either copy them whole (there’s a lot of files in there), or just copy these two files, whatever you prefer.
In external.php, on line 16 we’re going to add just one little bit of code to add that download attribute and filename (using a little bit of php to strip away the rest of the URL) to the link.
From this:
<a href="<?php echo esc_url( $product_url ); ?>" rel="nofollow" class="single_add_to_cart_button button alt"><?php echo $button_text; ?></a>
To this:
<a href="<?php echo esc_url( $product_url ); ?>" rel="nofollow" class="single_add_to_cart_button button alt" download="<?php echo basename($product_url); ?>"><?php echo $button_text; ?></a>
If we go back to the front-end and visit the product detail page, clicking the new ‘Download Now’ button should start the download automatically. But going to an archive page – like the shop page, or a category page – and clicking ‘Download Now’ will still have the default functionality – no automatic download. That’s where the add-to-cart.php file comes in.
This is pretty much the whole file, minus the template header:
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly global $product; echo apply_filters( 'woocommerce_loop_add_to_cart_link', sprintf( '<a href="%s" rel="nofollow" data-product_id="%s" data-product_sku="%s" class="button %s product_type_%s">%s</a>', esc_url( $product->add_to_cart_url() ), esc_attr( $product->id ), esc_attr( $product->get_sku() ), $product->is_purchasable() ? 'add_to_cart_button' : '', esc_attr( $product->product_type ), esc_html( $product->add_to_cart_text() ) ), $product );
What we need to do is to duplicate that code, add in our download attribute, and wrap it in code that says if it’s an ‘external’ product, use our modified link instead.
It looks like this:
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly global $product; if( $product->is_type( 'external' ) ){ $downloadURL = basename($product->add_to_cart_url()); echo apply_filters( 'woocommerce_loop_add_to_cart_link', sprintf( '<a href="%s" rel="nofollow" data-product_id="%s" data-product_sku="%s" class="button %s product_type_%s" download="%s">%s</a>', esc_url( $product->add_to_cart_url() ), esc_attr( $product->id ), esc_attr( $product->get_sku() ), $product->is_purchasable() ? 'add_to_cart_button' : '', esc_attr( $product->product_type ), $downloadURL, esc_html( $product->add_to_cart_text() ) ), $product ); } else { echo apply_filters( 'woocommerce_loop_add_to_cart_link', sprintf( '<a href="%s" rel="nofollow" data-product_id="%s" data-product_sku="%s" class="button %s product_type_%s">%s</a>', esc_url( $product->add_to_cart_url() ), esc_attr( $product->id ), esc_attr( $product->get_sku() ), $product->is_purchasable() ? 'add_to_cart_button' : '', esc_attr( $product->product_type ), esc_html( $product->add_to_cart_text() ) ), $product ); }
There you go. Now it works in both places. An argument can be made that the button could be removed entirely from the archive pages, forcing visitors to view the product detail page, say to get more information. That’s entirely viable, but in our case we’re going for impulse.
Finally, you may want to add the following to your theme’s styles.css file in order to match the button position of the ‘add to cart’ buttons:
.product_type_external { float: right; }
Here’s the files if you’d like them:
Please note: things change, so it might be a good idea to check the original Woocommerce template files against the code you see above. If it’s changed in any way, you should merge the changed files with the code above. That said, these files are pretty straightforward. I don’t see them changing often.
Easy solution is to simply zip the free file and it will force download. The template change is temporary as it will be rewritten during the first update of Woo. And Woo sometimes changes the internal template code so it will stop working anyway sooner or later.
Hi Zbynek – zipping the file is a possible solution, but for iPhone users is a very bad experience – iPhones don’t unzip files without the installation of a separate app and this itself creates multiple issues. The piece above walks you through the creation of template override files, so the Woo template files are not overwritten on update. Yes, Woo does update these files, but in many years of working with Woocommerce on a dozen or more sites, no template has ever stopped working. At most, in our experience, these changes will need to be merged once a year – not really a big deal, especially for the very minor changes above.
simply install this plugin to add a download button for free ,virtual and downloadable products in woocommerce https://wordpress.org/plugins/avenirsoft-directdownload/
Great tutorial! Just what I was looking for. Please, how can I remove the “Download Now” button from the archive page? Thanks for your wonderful anticipated response.