Module 3 · 3.3
English
Digital and virtual products
Module 3: Products · Reading time: 11 minutes
Learning objective: After this lesson you can sell digital and virtual products safely: you choose a secure download method, shield the download folder, set limits and handle the right of withdrawal for digital content correctly.
Key concepts: virtual product, downloadable product, download link, download limit, download expiry, download method (Force downloads, X-Accel-Redirect/X-Sendfile, Redirect only), woocommerce_uploads, .htaccess, nginx, Approved download directories, access after payment, digital content, express consent, waiver of the right of withdrawal
Virtual and downloadable: two different checkboxes
For a simple product or a variation you see two checkboxes. They look alike, but they do different things:
- Virtual means nothing is shipped. WooCommerce charges no shipping costs and does not ask for a shipping address at checkout (if everything in the cart is virtual). Think of a tea tasting on location, a gift card you send by email, or an online workshop.
- Downloadable means the customer gets one or more files after payment. WooCommerce creates a download link for each customer and shows it in the confirmation email and under My account > Downloads.
A digital recipe book as a PDF is usually both: nothing goes by post, and there is a file. A printed recipe book with a free PDF is downloadable but not virtual: the book does go by post.
Theehuis Example sells the "Receptenboek Thee en Taart" (Tea and Cake Recipe Book) as a PDF for €9.95. Checkboxes: virtual and downloadable.
How a download works, and why the method matters
When you upload a file for a downloadable product, WooCommerce puts it in the folder wp-content/uploads/woocommerce_uploads/. By default it adds a random string of characters to the file name (setting "Append a unique string to filename for security", on by default). The customer never gets that address, but a link to your shop with an order key and a download code. On every click WooCommerce checks: does this download belong to a paid order, has the limit not been reached, has it not expired? Only then does the customer get the file.
How the file then reaches the customer is chosen under WooCommerce > Settings > Products > Downloadable products, at the File download method:
| Method | How it works | Security |
|---|---|---|
| Force downloads (default) | PHP reads the file and sends it itself | The real address stays hidden. Large files can stall on some servers or hit the PHP time limit |
| X-Accel-Redirect/X-Sendfile | PHP checks, the web server sends the file | Just as secure and better for large files; the web server must support it (on Apache this needs the module mod_xsendfile, nginx has X-Accel-Redirect). Ask your hosting provider |
| Redirect only | WooCommerce redirects the customer to the real file address | Insecure: anyone who has the address can share it, and the file can be fetched without buying. WooCommerce itself calls it "Insecure" |
So choose Force downloads or X-Sendfile. Redirecting is only an emergency solution, and the setting "Allow using redirect mode (insecure) as a last resort" makes WooCommerce fall back to redirecting if the other method fails; leave it off unless you know why you need it.
Shielding the folder
With Force downloads or X-Sendfile, the folder woocommerce_uploads must be closed to ordinary visitors. Otherwise someone who guesses the file name or takes it from a leaked link can fetch the file directly. That is why WooCommerce puts two files in that folder during installation:
- an empty
index.html, so the folder does not show a list of files; - an
.htaccesswithdeny from all(with the Redirect only method:Options -Indexes).
That .htaccess file works on Apache and LiteSpeed (as at WebOké and many other shared hosting providers). On nginx the web server does not read .htaccess. There, a rule in the server configuration must block the folder. On managed nginx hosting the provider sometimes takes care of this; on your own VPS you have to do it yourself. WooCommerce checks this itself and shows a notice in the admin (and in Site Health) if the folder does not appear to be protected.
A few things to watch out for:
- An empty 200 is no proof. If you request the folder and see an empty page, that may be the empty
index.htmlwhile the files themselves are open. So also test one file (the exercise does this). - Files from elsewhere. For a product you can also enter a link to a file stored elsewhere. For this WooCommerce has the list of Approved download directories: only files from those folders or addresses may be used as downloads. That way nobody with admin rights can offer an arbitrary file from the server as a download on a product, whether by accident or on purpose. Keep that list short.
- Backups and staging. The folder is included in your backup. So a staging environment also contains your paid files: shield the staging site (lesson 7.3).
Limits and access
For each downloadable product or variation you set:
- Download limit: how often the customer may download. Empty means unlimited. A limit of, say, 5 reduces sharing, but leads to complaints when someone buys a new laptop. Choose something reasonable and help customers who ask.
- Download expiry: after how many days the link stops working.
General settings under Downloadable products:
- Downloads require login, off by default. On means guests cannot download anything; only turn it on if you also require accounts.
- Grant access to downloadable products after payment, on by default: the customer can download as soon as the order has the status Processing, so straight after a successful payment. If it is off, only after Completed.
Withdrawal for digital content
With an ordinary teapot the customer has 14 days to change their mind (lesson 5.2). With a download that is tricky: whoever has the PDF keeps it, even after withdrawing. That is why there is an exception, but only under conditions. In the EU it is in Article 16 of Directive 2011/83/EU; in the Netherlands in Article 6:230p(g) of the Dutch Civil Code (BW). There is no right of withdrawal for digital content not supplied on a tangible medium if:
- delivery has started with the consumer's prior express consent;
- the consumer has acknowledged that they thereby lose their right of withdrawal; and
- you have provided a confirmation of this (in the confirmation of the contract, on a durable medium such as the order email).
If any of these three is missing, the customer keeps their right of withdrawal, even if they have already downloaded. In Belgium and Germany the same EU rule applies through their own national law (see lesson 5.2).
WooCommerce does not handle this automatically. You need:
- a required checkbox at checkout, only when the cart contains digital content, with a text such as "I agree that delivery starts immediately, and I understand that I thereby lose my right of withdrawal";
- the same text as a confirmation in the order email for those products;
- the right sentence in your withdrawal information stating that this applies to downloads.
There are extensions that add such a checkbox; the Checkout block also has options for extra fields. Assess them as you would any plugin. A checkbox that is ticked in advance does not count as express consent (lesson 5.4).
Note the difference with virtual services, such as a workshop on a set date. The rules for services apply there, with different exceptions. Read lesson 5.2.
Summary
- Virtual = nothing shipped; downloadable = files after payment. A PDF is usually both.
- Choose Force downloads or X-Accel-Redirect/X-Sendfile; Redirect only is insecure.
- The folder
woocommerce_uploadsmust be closed:.htaccesson Apache and LiteSpeed, a server rule on nginx. Test a real file, not just the folder. - Keep the list of Approved download directories short and set reasonable limits.
- No right of withdrawal for downloads only with express consent, a waiver of the right and a confirmation; WooCommerce does not do this automatically. In the Netherlands this is Article 6:230p(g) of the Dutch Civil Code (BW).
Quiz
Exercise
Exercise A3.3: Are your downloads protected? This exercise requests paths that are not linked, so it only works for your own shop. First you prove the domain is yours: you add a TXT record _weboke-cursus.<jouw domein> with the code you receive, or you place a file /.well-known/weboke-cursus-<code>.txt containing that code. Then enter your shop's address and, if you like, the path of one download file as WooCommerce shows it for the product (it starts with /wp-content/uploads/woocommerce_uploads/). The program requests the folder (without following redirects, only the beginning) and, if you entered a path, requests the headers of that file once. Green if the folder returns 401, 403 or 404, or a page without a list of files, and the file returns 401, 403 or 404. Orange if you did not enter a file: then only the folder has been checked, and an empty page does not tell you enough. Red if the folder shows a list of files, or if the file can simply be downloaded (200): then anyone with the address can fetch it without buying. The program only stores the status codes, never the file.
A question for yourself (not checked): which download method is set in your shop, and how have you arranged withdrawal for your digital products?
Further reading
- Digital and downloadable product handling (woocommerce.com): https://woocommerce.com/document/digital-downloadable-product-handling/
- Free WordPress course 7.4: Hardening your website: capabilities, headers and security plugins
- Forbidden (403): You don't have permission to access / on this server
- Dutch Civil Code Book 6, Article 6:230p (wetten.overheid.nl, Dutch): https://wetten.overheid.nl/BWBR0005289/
The knowledge base describes the situation at WebOké (LiteSpeed, .htaccess works); other providers work in a similar way, except on nginx.
