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); $product_name = get_the_title($product_id); 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, $product_name); } else { self::deliver_protected_file($file_meta['file_path'], false, $product_name); } } else { self::deliver_protected_file($file_meta['file_path'], false, $product_name); } 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); $product_name = get_the_title($product_id); 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, $product_name); } else { self::deliver_protected_file($file_meta['file_path'], false, $product_name); } } else { self::deliver_protected_file($file_meta['file_path'], false, $product_name); } return; } } } // Regular file handling (backward compatibility) $enable_watermark = get_post_meta($product_id, '_wpdd_enable_watermark', true); // Generate proper filename for software license products $product_type = get_post_meta($product_id, '_wpdd_product_type', true); $final_filename = $file['name']; if ($product_type === 'software_license') { // Check if this is a package file (contains version info) if (strpos($file['url'], 'wpdd-packages/') !== false && preg_match('/package-v([^\/]+)\.zip$/', $file['url'], $matches)) { $version = $matches[1]; $product_name = get_the_title($product_id); // Create sanitized filename using product name and version $safe_name = str_replace([' ', '.'], ['-', '_'], $product_name . ' v' . $version); $safe_name = sanitize_file_name($safe_name); $final_filename = $safe_name . '.zip'; } } 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, $final_filename, true); } else { self::deliver_file($file['url'], $final_filename); } } else { self::deliver_file($file['url'], $final_filename); } } private static function show_file_selection($files, $order) { ?> > <?php _e('Select File to Download', 'wp-digital-download'); ?>

Original: %s', 'wp-digital-download'), $file_path, $original_path)); } wp_die(__('File not found. Please contact the administrator.', 'wp-digital-download')); } $file_size = filesize($file_path); $file_type = wp_check_filetype($file_path); if (empty($file_name)) { $file_name = basename($file_path); } nocache_headers(); header('Content-Type: ' . ($file_type['type'] ?: 'application/octet-stream')); header('Content-Disposition: attachment; filename="' . $file_name . '"'); header('Content-Length: ' . $file_size); header('Content-Transfer-Encoding: binary'); if (ob_get_level()) { ob_end_clean(); } readfile($file_path); if ($is_temp && file_exists($file_path)) { unlink($file_path); } exit; } private static function log_download($order, $product_id, $file_id) { global $wpdb; $wpdb->insert( $wpdb->prefix . 'wpdd_downloads', array( 'order_id' => $order->id, 'product_id' => $product_id, 'customer_id' => $order->customer_id, 'file_id' => $file_id, 'download_date' => current_time('mysql'), 'ip_address' => $_SERVER['REMOTE_ADDR'], 'user_agent' => $_SERVER['HTTP_USER_AGENT'] ), array('%d', '%d', '%d', '%s', '%s', '%s', '%s') ); } private static function is_watermarkable($file_url) { $supported_types = array('jpg', 'jpeg', 'png', 'gif', 'pdf'); $file_extension = strtolower(pathinfo($file_url, PATHINFO_EXTENSION)); return in_array($file_extension, $supported_types); } }