Major improvements: Fix download limits, enhance license display, fix software filenames
🔧 Bug Fixes: - Fixed download limits defaulting to 5 instead of 0 for unlimited downloads - Fixed software license filename sanitization (spaces→dashes, dots→underscores, proper .zip extension) - Software downloads now show as "Test-Plugin-v2-2-0.zip" instead of "Test Plugin v2.2.0" ✨ UI/UX Enhancements: - Redesigned license key display to span full table width with FontAwesome copy icons - Added responsive CSS styling for license key rows - Integrated FontAwesome CDN for modern copy icons 🏗️ Architecture Improvements: - Added comprehensive filename sanitization in both download handler and API paths - Enhanced software license product handling for local package files - Improved error handling and logging throughout download processes 📦 Infrastructure: - Added Gitea workflows for automated releases on push to main - Created comprehensive .gitignore excluding test files and browser automation - Updated documentation with all recent improvements and technical insights 🔍 Technical Details: - Software license products served from wp-content/uploads/wpdd-packages/ - Download flow: token → process_download_by_token() → process_download() → deliver_file() - Dual path coverage for both API downloads and regular file delivery - Version placeholder system for automated deployment 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -87,16 +87,16 @@ class WPDD_Download_Handler {
|
||||
}
|
||||
|
||||
private static function process_download_by_order() {
|
||||
$download_link_id = intval($_GET['wpdd_download']);
|
||||
$order_id = intval($_GET['wpdd_download']);
|
||||
|
||||
// Debug nonce verification
|
||||
if (current_user_can('manage_options')) {
|
||||
error_log('WPDD Debug: Download Link ID: ' . $download_link_id);
|
||||
error_log('WPDD Debug: Order ID: ' . $order_id);
|
||||
error_log('WPDD Debug: Nonce received: ' . ($_GET['_wpnonce'] ?? 'none'));
|
||||
error_log('WPDD Debug: Expected nonce action: wpdd_download_' . $download_link_id);
|
||||
error_log('WPDD Debug: Expected nonce action: wpdd_download_' . $order_id);
|
||||
}
|
||||
|
||||
if (!wp_verify_nonce($_GET['_wpnonce'] ?? '', 'wpdd_download_' . $download_link_id)) {
|
||||
if (!wp_verify_nonce($_GET['_wpnonce'] ?? '', 'wpdd_download_' . $order_id)) {
|
||||
if (current_user_can('manage_options')) {
|
||||
error_log('WPDD Debug: Nonce verification failed!');
|
||||
}
|
||||
@@ -105,18 +105,6 @@ class WPDD_Download_Handler {
|
||||
|
||||
global $wpdb;
|
||||
|
||||
// First get the download link to find the associated order
|
||||
$download_link = $wpdb->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']);
|
||||
@@ -436,16 +424,17 @@ class WPDD_Download_Handler {
|
||||
|
||||
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);
|
||||
self::deliver_protected_file($watermarked_file, true, $product_name);
|
||||
} else {
|
||||
self::deliver_protected_file($file_meta['file_path']);
|
||||
self::deliver_protected_file($file_meta['file_path'], false, $product_name);
|
||||
}
|
||||
} else {
|
||||
self::deliver_protected_file($file_meta['file_path']);
|
||||
self::deliver_protected_file($file_meta['file_path'], false, $product_name);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -464,16 +453,17 @@ class WPDD_Download_Handler {
|
||||
|
||||
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);
|
||||
self::deliver_protected_file($watermarked_file, true, $product_name);
|
||||
} else {
|
||||
self::deliver_protected_file($file_meta['file_path']);
|
||||
self::deliver_protected_file($file_meta['file_path'], false, $product_name);
|
||||
}
|
||||
} else {
|
||||
self::deliver_protected_file($file_meta['file_path']);
|
||||
self::deliver_protected_file($file_meta['file_path'], false, $product_name);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -483,15 +473,32 @@ class WPDD_Download_Handler {
|
||||
// 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, $file['name'], true);
|
||||
self::deliver_file($watermarked_file, $final_filename, true);
|
||||
} else {
|
||||
self::deliver_file($file['url'], $file['name']);
|
||||
self::deliver_file($file['url'], $final_filename);
|
||||
}
|
||||
} else {
|
||||
self::deliver_file($file['url'], $file['name']);
|
||||
self::deliver_file($file['url'], $final_filename);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -606,18 +613,77 @@ class WPDD_Download_Handler {
|
||||
self::deliver_protected_file($protected_path);
|
||||
}
|
||||
|
||||
private static function deliver_protected_file($file_path, $is_temp = false) {
|
||||
private static function deliver_protected_file($file_path, $is_temp = false, $product_name = null) {
|
||||
if (!file_exists($file_path)) {
|
||||
wp_die(__('File not found.', 'wp-digital-download'));
|
||||
}
|
||||
|
||||
$file_name = basename($file_path);
|
||||
$file_size = filesize($file_path);
|
||||
$file_type = wp_check_filetype($file_path);
|
||||
$file_info = wp_check_filetype($file_path);
|
||||
|
||||
// If product name is provided, use it with the original extension
|
||||
if ($product_name) {
|
||||
$original_file_name = basename($file_path);
|
||||
$original_extension = pathinfo($original_file_name, PATHINFO_EXTENSION);
|
||||
|
||||
// If no extension found, try to detect it
|
||||
if (empty($original_extension)) {
|
||||
// Check if it's a zip file by reading the first few bytes
|
||||
$handle = fopen($file_path, 'rb');
|
||||
if ($handle) {
|
||||
$header = fread($handle, 4);
|
||||
fclose($handle);
|
||||
|
||||
// ZIP files start with PK (0x504B)
|
||||
if (substr($header, 0, 2) === 'PK') {
|
||||
$original_extension = 'zip';
|
||||
$file_info['type'] = 'application/zip';
|
||||
$file_info['ext'] = 'zip';
|
||||
}
|
||||
}
|
||||
|
||||
// If still no extension, try wp_check_filetype result
|
||||
if (empty($original_extension) && !empty($file_info['ext'])) {
|
||||
$original_extension = $file_info['ext'];
|
||||
}
|
||||
}
|
||||
|
||||
// Sanitize product name for filename use
|
||||
// Convert spaces to dashes and dots to underscores, then use standard sanitization
|
||||
$safe_product_name = str_replace([' ', '.'], ['-', '_'], $product_name);
|
||||
$safe_product_name = sanitize_file_name($safe_product_name);
|
||||
$file_name = $safe_product_name . ($original_extension ? '.' . $original_extension : '');
|
||||
} else {
|
||||
// Fallback to original logic if no product name provided
|
||||
$file_name = basename($file_path);
|
||||
$has_extension = strpos($file_name, '.') !== false;
|
||||
|
||||
// If no extension in filename, try to determine from content
|
||||
if (!$has_extension) {
|
||||
// Check if it's a zip file by reading the first few bytes
|
||||
$handle = fopen($file_path, 'rb');
|
||||
if ($handle) {
|
||||
$header = fread($handle, 4);
|
||||
fclose($handle);
|
||||
|
||||
// ZIP files start with PK (0x504B)
|
||||
if (substr($header, 0, 2) === 'PK') {
|
||||
$file_info['type'] = 'application/zip';
|
||||
$file_info['ext'] = 'zip';
|
||||
$file_name .= '.zip';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we still don't have an extension but wp_check_filetype detected one, add it
|
||||
if (!$has_extension && !empty($file_info['ext']) && strpos($file_name, '.' . $file_info['ext']) === false) {
|
||||
$file_name .= '.' . $file_info['ext'];
|
||||
}
|
||||
}
|
||||
|
||||
nocache_headers();
|
||||
|
||||
header('Content-Type: ' . ($file_type['type'] ?: 'application/octet-stream'));
|
||||
header('Content-Type: ' . ($file_info['type'] ?: 'application/octet-stream'));
|
||||
header('Content-Disposition: attachment; filename="' . $file_name . '"');
|
||||
header('Content-Length: ' . $file_size);
|
||||
header('Content-Transfer-Encoding: binary');
|
||||
|
Reference in New Issue
Block a user