get_row($wpdb->prepare(
"SELECT * FROM {$wpdb->prefix}wpdd_download_links WHERE id = %d",
$download_link_id
));
if (!$download_link) {
wp_die(__('Invalid download link.', 'wp-digital-download'));
}
$order_id = $download_link->order_id;
// Check by email if guest
if (isset($_GET['customer_email']) && isset($_GET['key'])) {
$email = sanitize_email($_GET['customer_email']);
$key = sanitize_text_field($_GET['key']);
// Verify the key
$expected_key = substr(md5($email . AUTH_KEY), 0, 10);
if ($key !== $expected_key) {
wp_die(__('Invalid access key.', 'wp-digital-download'));
}
$order = $wpdb->get_row($wpdb->prepare(
"SELECT * FROM {$wpdb->prefix}wpdd_orders
WHERE id = %d AND customer_email = %s AND status = 'completed'",
$order_id,
$email
));
} elseif (is_user_logged_in()) {
$current_user = wp_get_current_user();
$order = $wpdb->get_row($wpdb->prepare(
"SELECT * FROM {$wpdb->prefix}wpdd_orders
WHERE id = %d AND (customer_id = %d OR customer_email = %s) AND status = 'completed'",
$order_id,
$current_user->ID,
$current_user->user_email
));
} else {
// For unregistered users, try to look up order by order number from URL if available
if (isset($_GET['order_id'])) {
$order_number = sanitize_text_field($_GET['order_id']);
// Look up order by order ID and verify it matches the order number
$order = $wpdb->get_row($wpdb->prepare(
"SELECT * FROM {$wpdb->prefix}wpdd_orders
WHERE id = %d AND order_number = %s AND status = 'completed'",
$order_id,
$order_number
));
if (current_user_can('manage_options')) {
error_log('WPDD Debug: Guest order lookup - Order ID: ' . $order_id . ', Order Number: ' . $order_number . ', Found: ' . ($order ? 'Yes' : 'No'));
}
if (!$order) {
wp_die(__('Invalid order or order not found.', 'wp-digital-download'));
}
} else {
// Debug: Show what parameters we have
$debug_info = '';
if (current_user_can('manage_options')) {
$debug_info = '
Debug info:
';
$debug_info .= 'GET params: ' . print_r($_GET, true);
$debug_info .= '
User logged in: ' . (is_user_logged_in() ? 'Yes' : 'No');
}
wp_die(__('You must be logged in to download this product or provide a valid order reference.', 'wp-digital-download') . $debug_info);
}
}
if (!$order) {
wp_die(__('Invalid order or you do not have permission to download this product.', 'wp-digital-download'));
}
self::process_download($order);
}
private static function process_download_by_token() {
$token = sanitize_text_field($_GET['wpdd_download_token']);
global $wpdb;
$download_link = $wpdb->get_row($wpdb->prepare(
"SELECT dl.*, o.*
FROM {$wpdb->prefix}wpdd_download_links dl
INNER JOIN {$wpdb->prefix}wpdd_orders o ON dl.order_id = o.id
WHERE dl.token = %s",
$token
));
if (!$download_link) {
wp_die(__('Invalid download link.', 'wp-digital-download'));
}
if ($download_link->expires_at < current_time('mysql')) {
// Check if user still has downloads remaining
if ($download_link->max_downloads > 0 && $download_link->download_count >= $download_link->max_downloads) {
wp_die(__('This download link has expired and you have no downloads remaining.', 'wp-digital-download'));
}
// Only send refresh email if this appears to be a real user attempt (not automated)
// Check if the customer is unregistered (has no user account)
$is_unregistered_customer = ($download_link->customer_id == 0);
if ($is_unregistered_customer) {
// Generate new token and send refresh email only for unregistered customers
$new_token = self::refresh_download_token($download_link->order_id, $download_link->customer_email);
if ($new_token) {
wp_die(sprintf(
__('Your download link has expired. A new download link has been sent to %s. Please check your email and try again.', 'wp-digital-download'),
esc_html($download_link->customer_email)
));
} else {
wp_die(__('This download link has expired and could not be refreshed. Please contact support.', 'wp-digital-download'));
}
} else {
// For registered users, just show expired message (they can log in to get new links)
wp_die(__('This download link has expired. Please log in to your account to get a new download link.', 'wp-digital-download'));
}
}
if ($download_link->max_downloads > 0 && $download_link->download_count >= $download_link->max_downloads) {
wp_die(__('Download limit exceeded.', 'wp-digital-download'));
}
$wpdb->update(
$wpdb->prefix . 'wpdd_download_links',
array('download_count' => $download_link->download_count + 1),
array('id' => $download_link->id),
array('%d'),
array('%d')
);
self::process_download($download_link);
}
/**
* Refresh an expired download token and send new link via email
*/
private static function refresh_download_token($order_id, $customer_email) {
global $wpdb;
// Generate new token with extended expiry (72 hours as suggested)
$new_token = wp_hash(uniqid() . $order_id . time());
$new_expires_at = date('Y-m-d H:i:s', strtotime('+72 hours'));
// Update the existing download link with new token and expiry
$updated = $wpdb->update(
$wpdb->prefix . 'wpdd_download_links',
array(
'token' => $new_token,
'expires_at' => $new_expires_at,
'refreshed_at' => current_time('mysql')
),
array('order_id' => $order_id),
array('%s', '%s', '%s'),
array('%d')
);
if (!$updated) {
return false;
}
// Send refresh email
self::send_refresh_email($order_id, $new_token, $customer_email);
return $new_token;
}
/**
* Send refresh email with new download link
*/
private static function send_refresh_email($order_id, $token, $customer_email) {
global $wpdb;
// Get order details
$order = $wpdb->get_row($wpdb->prepare(
"SELECT o.*, p.post_title as product_name
FROM {$wpdb->prefix}wpdd_orders o
LEFT JOIN {$wpdb->posts} p ON o.product_id = p.ID
WHERE o.id = %d",
$order_id
));
if (!$order) {
return false;
}
$download_url = add_query_arg(array(
'wpdd_download_token' => $token
), home_url());
$subject = sprintf(__('New Download Link for %s', 'wp-digital-download'), $order->product_name);
$message = sprintf(
__("Hello %s,\n\nYour download link for \"%s\" has expired, so we've generated a new one for you.\n\nThis new link is valid for 72 hours and can be used for your remaining downloads.\n\nDownload Link: %s\n\nOrder Number: %s\nPurchase Date: %s\n\nIf you have any issues, please contact our support team.\n\nBest regards,\n%s", 'wp-digital-download'),
$order->customer_name,
$order->product_name,
$download_url,
$order->order_number,
date_i18n(get_option('date_format'), strtotime($order->purchase_date)),
get_bloginfo('name')
);
$headers = array('Content-Type: text/plain; charset=UTF-8');
return wp_mail($customer_email, $subject, $message, $headers);
}
/**
* Create download token for orders that don't have one (legacy orders)
*/
public static function ensure_download_token($order_id) {
global $wpdb;
// Check if token already exists
$existing_token = $wpdb->get_var($wpdb->prepare(
"SELECT token FROM {$wpdb->prefix}wpdd_download_links WHERE order_id = %d",
$order_id
));
if ($existing_token) {
return $existing_token;
}
// Create new token for legacy order
$token = wp_hash(uniqid() . $order_id . time());
$expires_at = date('Y-m-d H:i:s', strtotime('+7 days'));
$wpdb->insert(
$wpdb->prefix . 'wpdd_download_links',
array(
'order_id' => $order_id,
'token' => $token,
'expires_at' => $expires_at,
'max_downloads' => 5,
'created_at' => current_time('mysql')
),
array('%d', '%s', '%s', '%d', '%s')
);
return $token;
}
private static function process_download($order) {
$product_id = $order->product_id;
$files = get_post_meta($product_id, '_wpdd_files', true);
// Debug output for admins
if (current_user_can('manage_options') && empty($files)) {
wp_die(sprintf(__('Debug: No files found for product ID %d. Files data: %s', 'wp-digital-download'),
$product_id, '
' . print_r($files, true) . '')); } if (empty($files)) { wp_die(__('No files available for download.', 'wp-digital-download')); } // Debug output for admins if (current_user_can('manage_options')) { error_log('WPDD Debug: Files for product ' . $product_id . ': ' . print_r($files, true)); } $download_limit = get_post_meta($product_id, '_wpdd_download_limit', true); $download_expiry = get_post_meta($product_id, '_wpdd_download_expiry', true); if ($download_expiry > 0) { $expiry_date = date('Y-m-d H:i:s', strtotime($order->purchase_date . ' + ' . $download_expiry . ' days')); if (current_time('mysql') > $expiry_date) { wp_die(__('Your download period has expired.', 'wp-digital-download')); } } if ($download_limit > 0 && $order->download_count >= $download_limit) { wp_die(__('You have reached the download limit for this product.', 'wp-digital-download')); } global $wpdb; $wpdb->update( $wpdb->prefix . 'wpdd_orders', array('download_count' => $order->download_count + 1), array('id' => $order->id), array('%d'), array('%d') ); $file_index = isset($_GET['file']) ? intval($_GET['file']) : 0; // Handle array structure - files might be indexed or not $file_list = array_values($files); // Reindex to ensure numeric keys if (count($file_list) > 1 && !isset($_GET['file'])) { self::show_file_selection($file_list, $order); exit; } if (!isset($file_list[$file_index])) { // Debug output for admins if (current_user_can('manage_options')) { wp_die(sprintf(__('Debug: File index %d not found. Available files: %s', 'wp-digital-download'), $file_index, '
' . print_r($file_list, true) . '')); } wp_die(__('File not found.', 'wp-digital-download')); } $file = $file_list[$file_index]; self::log_download($order, $product_id, $file['id'] ?? $file_index); // Debug for admins if (current_user_can('manage_options')) { error_log('WPDD Debug: Processing file - ID: ' . ($file['id'] ?? 'none') . ', URL: ' . ($file['url'] ?? 'none')); } // Check if this is a protected file if (isset($file['id']) && strpos($file['id'], 'wpdd_') === 0) { // This is a protected file, get its metadata $file_meta = get_option('wpdd_protected_file_' . $file['id']); if (current_user_can('manage_options')) { error_log('WPDD Debug: Protected file detected - ' . $file['id']); error_log('WPDD Debug: File meta exists: ' . ($file_meta ? 'Yes' : 'No')); if ($file_meta) { error_log('WPDD Debug: File path exists: ' . (file_exists($file_meta['file_path']) ? 'Yes' : 'No')); } } if ($file_meta && file_exists($file_meta['file_path'])) { $enable_watermark = get_post_meta($product_id, '_wpdd_enable_watermark', true); if ($enable_watermark && self::is_watermarkable($file_meta['file_path'])) { $watermarked_file = WPDD_Watermark::apply_watermark($file_meta['file_path'], $order); if ($watermarked_file) { self::deliver_protected_file($watermarked_file, true); } else { self::deliver_protected_file($file_meta['file_path']); } } else { self::deliver_protected_file($file_meta['file_path']); } return; } } // Check if URL contains protected download parameter (alternative check) if (isset($file['url']) && strpos($file['url'], 'wpdd_protected_download=') !== false) { // Extract file_id from URL if (preg_match('/wpdd_protected_download=([^&]+)/', $file['url'], $matches)) { $file_id = $matches[1]; $file_meta = get_option('wpdd_protected_file_' . $file_id); if (current_user_can('manage_options')) { error_log('WPDD Debug: Protected URL detected - ' . $file_id); } if ($file_meta && file_exists($file_meta['file_path'])) { $enable_watermark = get_post_meta($product_id, '_wpdd_enable_watermark', true); if ($enable_watermark && self::is_watermarkable($file_meta['file_path'])) { $watermarked_file = WPDD_Watermark::apply_watermark($file_meta['file_path'], $order); if ($watermarked_file) { self::deliver_protected_file($watermarked_file, true); } else { self::deliver_protected_file($file_meta['file_path']); } } else { self::deliver_protected_file($file_meta['file_path']); } return; } } } // Regular file handling (backward compatibility) $enable_watermark = get_post_meta($product_id, '_wpdd_enable_watermark', true); if ($enable_watermark && self::is_watermarkable($file['url'])) { $watermarked_file = WPDD_Watermark::apply_watermark($file['url'], $order); if ($watermarked_file) { self::deliver_file($watermarked_file, $file['name'], true); } else { self::deliver_file($file['url'], $file['name']); } } else { self::deliver_file($file['url'], $file['name']); } } private static function show_file_selection($files, $order) { ?> >