Skip to content

Sell digital products in Laravel: private files, download limits and expiry ​

A shop that sells files has one job the rest of the shop does not: the file has to reach whoever paid and nobody else. The link goes into an email, the email gets forwarded, and a mail scanner opens it before the buyer does. Then the buyer writes in, and someone has to help them without touching the database.

kitloom's shop now does all of that, on WooCommerce's own data. A product brought over keeps its files, a customer keeps their permissions, and a link from an old email keeps working.

Where the file lives ​

An uploaded file goes to a folder outside the public one, or to a disk you name with SHOP_DOWNLOADS_DISK. The only way to it is a buyer's link. kitloom/backup takes that folder along with the uploads, so a backup does not lose what you sell.

A file can also sit at an address elsewhere. The buyer is then sent there and sees that address, and the form says so.

WooCommerce keeps its files in uploads/woocommerce_uploads behind an .htaccess, which nginx does not read, so on many servers anyone with the address gets the file. php artisan shop:downloads-secure says what would move, and with --apply moves it to the private folder. Buyers keep their links and what they have left.

Limits that hold ​

The link is WooCommerce's, /?download_file=…, and a limit and an expiry work as they do there. The tests run the same order through a real WooCommerce and through kitloom: the count, what is left and the log come out the same.

kitloom is stricter in three places, on purpose. WooCommerce does not check a request for part of a file, so a Range header gets past its limit; here a download resumed within half an hour is the same download, and after that it needs one left. A path elsewhere on the server is refused, so a stored value cannot hand out .env. And a refunded variation loses its files, which WooCommerce leaves in place.

What the buyer sees ​

Downloads in the account, the order's page, "order received", and the customer's emails. A file that ran out stays listed with why and without a link, so a file someone paid for does not silently vanish. Every theme with an account draws it, and a new one gets it from the generator.

Sell a file: a downloadable product, its limit and its expiry

When a buyer writes in ​

An order with a file shows what the buyer has of each one. Give back adds a download, Change sets what is left and the last day, Revoke ends the link, and Grant access gives an old order a file added since. Each leaves a note on the order. The link is there to copy and not to open, because a click from the admin would use up a download.

Help a buyer with a download: what is left, the last day, access

An AI agent connected to the site can change what is left and the last day with order_download_update, and set a product's files with product_save. It never sees a customer's link, and it deletes nothing: taking a file away is remaining: 0, which a person can undo.

Try it ​

Open a sandbox in one click, with no sign-up: Filament or Nova. The shop's guide has the details, and moving from WooCommerce covers the rest of a shop.

Last updated:

kitloom — modules and themes for Laravel.
Contact · Pricing · Services · License · Refunds · Privacy · Community · YouTube · [email protected]