Skip to main content

Digital Downloads Enhanced

Overview​

The Digital Downloads module replaces WooCommerce's own download URLs with tokenised links it owns. Each downloadable line of a paid order gets one link with its own download limit and expiry; every attempt is checked and logged; and a link can be reset or revoked from the admin API.

It is for stores selling files that want per-link limits, expiry, an audit trail of who fetched what, and optional restriction by IP.

Availability​

ItemValue
Module keydigital_downloads
TierPremium
Entitlement keydigital_downloads
Admin tabdownloads, under Operations
Enabled optionaiowc_module_enabled_digital_downloads (off until turned on)
REST namespaceaiowc/v1

Enabling the module creates the three tables below, seeds the defaults and schedules the two jobs.

Settings​

Stored in the bundled option row aiowc_dd_settings; legacy per-key options aiowc_dd_<key> are migrated on first read.

API nameStored keyDefaultMeaning
defaultDownloadLimitdefault_download_limit3Downloads allowed per issued link.
defaultExpiryDaysdefault_expiry_days7Days a newly issued link stays valid.
enableIpRestrictionenable_ip_restrictionfalseApply the link's IP rules and the distinct-IP cap.
maxIpsPerDownloadmax_ips_per_download2Distinct IPs a link may be used from. 0 means unlimited.
enableDownloadLoggingenable_download_loggingtrueWrite a log row for each allowed and refused attempt.
cleanupDayscleanup_days90Age at which log rows are deleted.
linkTokenLengthlink_token_length32Length of the generated token.
forceDownloadforce_downloadtrueStream the file through WooCommerce's forced-download path where the file is local; otherwise redirect to it.

Five further settings are stored and returned by the settings routes but are not read anywhere in the module, so changing them has no effect in this release: enable_secure_links, enable_pdf_watermark, watermark_text, redirect_after_download and redirect_url.

How a download works​

  1. On woocommerce_order_status_completed or woocommerce_payment_complete, one link row is issued per downloadable line, taking its limit from default_download_limit and its expiry from default_expiry_days.
  2. woocommerce_customer_available_downloads is filtered so My Account and the order emails point at the token URL, ?aiowc_download=<token>, rather than WooCommerce's own.
  3. On template_redirect (priority 5) a request carrying that query variable is served. The token must match [a-f0-9]{16,128}; an unknown token is a 404.
  4. The link is evaluated in order: active, not expired, under its download limit, and — when IP restriction is on — allowed by the link's IP rules and under the distinct-IP cap.
  5. A refusal is logged (when logging is on) and answered with 403 and a specific message: expired, limit reached, or not permitted from this location.
  6. An allowed request writes a started log row, increments the download count, marks the row completed, fires aiowc_secure_download_served, and delivers the file through WC_Download_Handler.
  7. On woocommerce_order_status_refunded or woocommerce_order_status_cancelled the order's links are revoked.

Delivery uses WC_Download_Handler::download_file_force() for a local file when force_download is on, and download_file_redirect() otherwise. With WooCommerce inactive the request is refused with a 500 rather than served.

Admin screen​

The Downloads tab lists active download permissions — customer, product, downloads left and access expiry — with a refresh control. It reads GET /downloads/permissions and directs the user to the order edit screen to change a permission.

REST API endpoints​

All routes are on aiowc/v1 and require manage_woocommerce, plus a REST nonce on cookie-authenticated requests. The customer-facing path is the token URL above, not a REST route.

MethodPathPurposeRequired args
GET/downloads/permissionsList issued links; accepts page, per_page, order_id, user_id.–
GET/downloads/links/{id}/logsAttempt log for one link; accepts page, per_page.id
POST/downloads/links/{id}/resetReset a link's used-download count.id
POST/downloads/links/{id}/revokeRevoke a link.id
GET/downloads/stats/{product_id}Download statistics for one product.product_id
GET/downloads/settingsRead the settings above.–
PUT / PATCH / POST/downloads/settingsUpdate the settings above.–

WooCommerce integration​

HookPriorityWhat the module does
woocommerce_order_status_completed10Issues one tokenised link per downloadable line.
woocommerce_payment_complete10Same, for gateways that complete payment without a status change.
woocommerce_order_status_refunded10Revokes the order's links.
woocommerce_order_status_cancelled10Revokes the order's links.
woocommerce_customer_available_downloads20Rewrites My Account and email download URLs to the token URL.
template_redirect5Serves ?aiowc_download=<token>.

The module fires aiowc_secure_download_served with the link row and the requesting IP after a successful delivery, which other code can hook.

Database schema​

TableHolds
{prefix}aiowc_download_linksOne row per issued link: order, product, download id, token, limit, count used, expiry, active flag.
{prefix}aiowc_download_logsEvery attempt: link, user, order, product, IP, user agent, status, file path and failure reason.
{prefix}aiowc_download_restrictionsPer-link IP rules, consulted only while enableIpRestriction is on.

There is no admin route for editing the restriction rows; the table is read by the access check but written to only outside this module's REST surface.

Background jobs​

HookScheduleWork
aiowc_digital_downloads_expire_linksHourlyMarks links past their expiry.
aiowc_digital_downloads_cleanupDailyDeletes log rows older than cleanupDays (minimum 1 day).

Entitlement limits​

digital_downloads is an on/off grant with no licence-side quota. The limits a customer meets — downloads per link, days of validity, distinct IPs — are all store settings.

Health check​

The module reports a warning when its tables are missing or WooCommerce is inactive, and otherwise reports that it is functioning normally.