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:
2025-09-09 19:16:57 -07:00
parent ce48f1615f
commit a160fe3964
28 changed files with 3709 additions and 156 deletions

View File

@@ -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');