The Downloadable Products plugin (plg_solidshop_downloadable) adds a
Downloadable product type to Solidshop for selling digital files
— eBooks, ZIP archives, audio, video, software, design assets. Each product
carries one or more files managed from a dedicated tab on the product edit form.
After purchase, customers collect their files from an
Account → Downloads page through token-secured download links
with an optional per-product download limit and link expiry.
Files are stored and served from your own Joomla installation — no third-party file-delivery service, no external bandwidth bill. The plugin is free; see the Downloadable Products extension page for the feature overview.
Requirements
- Joomla 6.0 or later
- PHP 8.4 or later
- Solidshop 1.4.0 or later (the installer enforces this)
- Enough disk space for the files you plan to sell — they live inside your Joomla installation (see Storage & security)
Installation
The download from solidshop.app is a single Joomla package,
Solidshop_Downloadable_v1.0.0.zip, holding two
extensions: the Downloadable plugin itself and a small companion scheduler plugin
(plg_task_solidshopdownloads) that cleans up expired download tokens.
One upload installs both, one update notice refreshes both, and uninstalling the
package removes both.
In your Joomla admin, go to
System → Install → Extensions and upload
Solidshop_Downloadable_v1.0.0.zip. Joomla installs both plugins
from the package and creates the two database tables
(#__sshop_download_files,
#__sshop_download_tokens). The installer refuses to run against
a Solidshop older than 1.4.0, before either plugin is touched.
Go to System → Manage → Plugins, search for downloadable, and enable Solidshop - Downloadable. Then search for download token and enable Solidshop - Download Token Cleanup. Like every Joomla plugin, both are disabled by default after install.
Open any product under Solidshop → Products. The Product type dropdown now offers Downloadable alongside Physical. There is no separate component option to switch on — enabling the plugin is all it takes.
Plugin settings
Both settings live on the plugin itself: System → Plugins → Solidshop - Downloadable.
| Setting | Default | What it does |
|---|---|---|
| Download Storage Base Path | files/shop |
Base directory, relative to the Joomla root, where uploaded files are stored.
Files are organised under {base}/{store_id}/downloads/.
See Storage & security before changing this on a
live store. |
| Allowed File Types | pdf, zip, rar, 7z, tar, gz, epub, mobi, mp3, mp4, ogg, wav, jpg, jpeg, png, gif, doc, docx, xls, xlsx, ppt, pptx, exe, dmg, apk | Comma-separated allowlist of file extensions accepted by the upload form. Trim it down or extend it as your catalogue needs. Regardless of this list, server-executable uploads (PHP, HTML, shell scripts) are rejected by a content-type check. |
Creating a downloadable product
Create or edit a product and set Product type to Downloadable. Save once — a new Downloads tab appears on the edit form. (The file manager needs a saved product to attach files to, so the tab is empty-handed on an unsaved product.)
In the Downloads tab, click Add file, pick the file, and optionally give it a display name (what the customer sees; defaults to the original filename). A product can carry any number of files — ship an eBook as PDF + ePub + MOBI, or an album as MP3 + FLAC + cover art. Drag rows by the handle to reorder; uploads, deletes, and reordering all happen inline without a page reload.
Two per-product fields at the top of the tab control delivery:
- Download Limit — how many times each file can be
downloaded per purchase.
0= unlimited. - Download Expiry — how long the download links stay
valid after purchase, in seconds
(e.g.
2592000= 30 days).0= links never expire.
Files apply to the whole product. Every file uploaded in the Downloads tab is delivered for every variant of the product. Where different buyers should receive different files (say, a Personal vs. Team licence package), create separate products.
What customers see
| Location | What renders |
|---|---|
| Product page — Download Info tab | A summary box: “instant download”, the download limit (“5 download(s) per purchase” or unlimited), and the link validity (shown in days, or “no expiry”). |
| Product page — Downloadable layout | The plugin also registers a dedicated Downloadable option in the product’s Layout dropdown. With that layout selected, the download info renders inline in the page body and the separate tab is skipped. |
| Account → Downloads | Every file the logged-in customer is entitled to, across all their orders: product, file, order link, remaining downloads, expiry date, and a Download button. Exhausted or expired rows stay listed but the button is disabled with the reason shown. |
The Downloads page lists account orders only. It shows files for orders that belong to the logged-in user; an order placed as a guest never appears there. Guest purchases are delivered by email instead — the order confirmation and payment-received emails carry the direct download links, which work without a login (see Email delivery).
How delivery works
When an order is created, the plugin generates one download token
per file, per order line — a random 64-character key stored in
#__sshop_download_tokens together with the download counter, the
product’s download limit, and the computed expiry date. The customer’s
Download button requests
index.php?option=com_solidshop&task=Download.file&token=…;
the controller validates the token, checks expiry and the remaining count, increments
the counter, and streams the file as an attachment. An expired or exhausted token
answers with HTTP 410 instead of the file.
- Tokens are per purchase — buying the same product again on a later order issues fresh tokens with a fresh counter and expiry.
- The expiry clock starts when the order is created, not on first download.
- The raw file path never appears in any URL; only the token does.
Downloads unlock only when payment is confirmed. Tokens are created when the order is placed, but the download endpoint and the account page both require the order’s payment status to be Paid (or Partially refunded — a partial refund on a mixed order does not cut off its digital lines). Until then the account page shows the row with an Awaiting Payment badge and no Download button — relevant for payment methods where payment arrives later (bank transfer, cash on delivery). A fully refunded order loses download access the same way.
Email delivery
When an order contains downloadable products, a “Your downloads” block is added to two of the store’s order emails, listing every file as a direct download link grouped per order line:
- Order confirmation — sent when the order is placed. If payment is still pending at that point (bank transfer, cash on delivery), the block says the links unlock automatically once payment is confirmed; the same links start working the moment the order is marked Paid.
- Payment received — sent when the order’s payment status changes to Paid, including a manual change on the admin order screen. For orders that contain downloads this email is the “your files are ready” notice, so it is sent even when the store’s Payment received email toggle is off (with the toggle on, it goes out for every order as usual). On an order with nothing to ship (no shipping rate — typical for digital-only orders) this email says the order is complete instead of promising a shipping confirmation.
For customers with an account the block also links to Account → Downloads. For guest orders the emailed links are the delivery channel: the download URL carries the secret token and requires no login, and the usual limit, expiry, and payment-status checks apply to every request.
Customised email templates: the block is injected via the
{% include 'downloadable/downloads.twig' ignore missing %} line in
the default Order confirmation and Payment received bodies.
If you edited those templates before this feature shipped, the email editor
shows an update banner — reset the body to the new default, or add that
include line to your customised body where you want the block to appear.
Storage & security
Uploaded files are stored under
{base}/{store_id}/downloads/ inside your Joomla root, where
{base} is the Download Storage Base Path setting
(default files/shop). Filenames are sanitised on upload and suffixed
with a random 16-character token, so the on-disk name cannot be guessed from the
product; the customer-facing display name is stored separately, so you can rename
what the buyer sees without touching the file on disk.
Because the default storage path sits inside the web root, the plugin protects the directory in depth — the same scheme Solidshop uses for cached invoice PDFs:
- Deny-all guard files (
.htaccessfor Apache/LiteSpeed,web.configfor IIS, and an emptyindex.html) are dropped into the directory automatically and re-created if they go missing. - The random filename suffix keeps direct URLs unguessable even on servers that ignore those guard files.
On nginx, add a deny rule. nginx honours neither
.htaccess nor web.config — there the random
filename suffix is the effective protection. For belt and braces, add a
location block denying direct access to the storage directory,
or point the base path at a directory outside the web root.
Two more upload safeguards run server-side regardless of configuration: the extension allowlist from the plugin settings, and a MIME inspection that rejects server-executable content (PHP, HTML, shell scripts) even under an allowed extension. Uploading files requires the Solidshop Manage Products permission.
Scheduled token cleanup
Expired tokens keep answering “link expired” correctly whether or not you clean them up — the cleanup task just stops the token table growing forever. The companion plugin registers a task type named Solidshop: Expired Download Token Cleanup which deletes tokens whose expiry date has passed.
Go to System → Scheduled Tasks → New, pick Solidshop: Expired Download Token Cleanup, and give it a schedule. Daily is plenty.
Joomla’s scheduler itself must be triggered — by the Web Cron URL,
a real cron job running cli/joomla.php scheduler:run, or the
lazy-scheduler system plugin. If you already run other Solidshop tasks (email
queue, invoices), the same trigger covers this one.
Customising the look
The customer-facing templates are standard Joomla layout files and can be overridden in your template without touching the plugin — your changes survive updates.
| What | Override path in your template |
|---|---|
| Account → Downloads page | html/com_solidshop/account/downloads.php |
| Download info box (product page) | html/layouts/com_solidshop/product/download_info.php |
| Dedicated Downloadable product layout | html/com_solidshop/product/downloadable.php |
Troubleshooting
No “Downloadable” option in the product type dropdown
- Confirm Solidshop - Downloadable is Enabled under System → Plugins — the type list is built from enabled plugins on every page load.
The Downloads tab is missing on the product edit form
- The tab only appears when the product’s type is set to Downloadable — switch the type and save first.
A file upload is rejected
- Check the extension against the Allowed File Types list in the plugin settings — the error message names the allowed types.
- Large files can trip PHP’s
upload_max_filesizeandpost_max_sizebefore Solidshop sees them; raise both for heavyweight products. - Check that the storage directory is writable by the web server — the
plugin creates the per-store
downloads/folder on first upload.
A customer says their downloads page is empty
- The page lists orders belonging to the logged-in account. An order placed as a guest, or under a different account, will not appear — point the customer at the download links in their order confirmation or payment-received email instead (see Email delivery).
- Rows show Awaiting Payment (with no Download button) until the order’s payment status is Paid — check the order if the customer paid by bank transfer or another delayed method.
- Tokens are only created for order lines whose product was Downloadable at the time of purchase — switching a product’s type later does not retrofit past orders.
“Link expired” or “limit reached” on download
- Both are per purchase, from the product’s settings at order time. To grant a customer more downloads, the simplest route is a fresh (zero-priced, if you like) order for the product.
- Raising the product’s limit or expiry affects future purchases only — existing tokens keep the values they were issued with.
“File not found” on a previously working download
- The file was deleted or moved on disk, or the Download Storage Base Path was changed after upload. File paths are stored relative to the base path, so changing the setting re-points every existing download — move the files along with it.
Uninstalling
Uninstall the Solidshop Downloadable Package from System → Manage → Extensions (filter by type Package). That removes the plugin and the cleanup task plugin together and drops both tables — every file record and every customer’s download tokens. The two plugins cannot be uninstalled separately: the task plugin deletes from a table the Downloadable plugin owns, so the package keeps them in step. Existing orders are untouched, but customers lose access to their files. The uploaded files themselves are left on disk under the storage directory; remove them manually if you want a clean sweep. If you only want to pause selling digital products, disable the plugin instead — the data stays intact.
Removing Solidshop entirely? Uninstall the add-ons first. Solidshop refuses to uninstall while add-on plugins such as this one are still installed, and names them in the error message. The order matters: an add-on’s own uninstall depends on the core tables and library still being present.