🔧 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>
		
			
				
	
	
		
			211 lines
		
	
	
		
			7.2 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			211 lines
		
	
	
		
			7.2 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
<?php
 | 
						|
/**
 | 
						|
 * Email handler class for WP Digital Download
 | 
						|
 * Handles email sending with logging and SMTP configuration
 | 
						|
 */
 | 
						|
 | 
						|
if (!defined('ABSPATH')) {
 | 
						|
    exit;
 | 
						|
}
 | 
						|
 | 
						|
class WPDD_Email {
 | 
						|
    
 | 
						|
    public static function init() {
 | 
						|
        // Configure SMTP if enabled
 | 
						|
        if (get_option('wpdd_smtp_enabled')) {
 | 
						|
            add_action('phpmailer_init', array(__CLASS__, 'configure_smtp'));
 | 
						|
        }
 | 
						|
    }
 | 
						|
    
 | 
						|
    /**
 | 
						|
     * Send email with logging
 | 
						|
     * 
 | 
						|
     * @param string $to Email address to send to
 | 
						|
     * @param string $subject Email subject
 | 
						|
     * @param string $message Email message (HTML)
 | 
						|
     * @param string $email_type Type of email for logging (e.g., 'order_confirmation', 'download_link', etc.)
 | 
						|
     * @param array $headers Optional email headers
 | 
						|
     * @return bool Whether email was sent successfully
 | 
						|
     */
 | 
						|
    public static function send($to, $subject, $message, $email_type = 'general', $headers = array()) {
 | 
						|
        global $wpdb;
 | 
						|
        
 | 
						|
        // Set default headers if not provided
 | 
						|
        if (empty($headers)) {
 | 
						|
            $from_email = get_option('wpdd_from_email', get_option('admin_email'));
 | 
						|
            $from_name = get_option('wpdd_from_name', get_bloginfo('name'));
 | 
						|
            
 | 
						|
            $headers = array(
 | 
						|
                'From: ' . $from_name . ' <' . $from_email . '>',
 | 
						|
                'Content-Type: text/html; charset=UTF-8'
 | 
						|
            );
 | 
						|
        }
 | 
						|
        
 | 
						|
        // Send the email
 | 
						|
        $sent = wp_mail($to, $subject, $message, $headers);
 | 
						|
        
 | 
						|
        // Log the email
 | 
						|
        $table_name = $wpdb->prefix . 'wpdd_email_logs';
 | 
						|
        
 | 
						|
        // Create table if it doesn't exist
 | 
						|
        if ($wpdb->get_var("SHOW TABLES LIKE '$table_name'") != $table_name) {
 | 
						|
            self::create_email_logs_table();
 | 
						|
        }
 | 
						|
        
 | 
						|
        // Get error message if failed
 | 
						|
        $error_message = '';
 | 
						|
        if (!$sent) {
 | 
						|
            global $phpmailer;
 | 
						|
            if (isset($phpmailer) && is_object($phpmailer) && !empty($phpmailer->ErrorInfo)) {
 | 
						|
                $error_message = $phpmailer->ErrorInfo;
 | 
						|
            }
 | 
						|
        }
 | 
						|
        
 | 
						|
        // Insert log entry
 | 
						|
        $wpdb->insert(
 | 
						|
            $table_name,
 | 
						|
            array(
 | 
						|
                'to_email' => $to,
 | 
						|
                'subject' => $subject,
 | 
						|
                'message' => $message,
 | 
						|
                'status' => $sent ? 'sent' : 'failed',
 | 
						|
                'email_type' => $email_type,
 | 
						|
                'error_message' => $error_message,
 | 
						|
                'sent_at' => current_time('mysql')
 | 
						|
            ),
 | 
						|
            array('%s', '%s', '%s', '%s', '%s', '%s', '%s')
 | 
						|
        );
 | 
						|
        
 | 
						|
        return $sent;
 | 
						|
    }
 | 
						|
    
 | 
						|
    /**
 | 
						|
     * Configure SMTP settings for PHPMailer
 | 
						|
     */
 | 
						|
    public static function configure_smtp($phpmailer) {
 | 
						|
        $phpmailer->isSMTP();
 | 
						|
        $phpmailer->Host = get_option('wpdd_smtp_host');
 | 
						|
        $phpmailer->Port = get_option('wpdd_smtp_port', 587);
 | 
						|
        $phpmailer->SMTPAuth = true;
 | 
						|
        $phpmailer->Username = get_option('wpdd_smtp_username');
 | 
						|
        $phpmailer->Password = get_option('wpdd_smtp_password');
 | 
						|
        $phpmailer->SMTPSecure = get_option('wpdd_smtp_encryption', 'tls');
 | 
						|
        $phpmailer->From = get_option('wpdd_from_email', get_option('admin_email'));
 | 
						|
        $phpmailer->FromName = get_option('wpdd_from_name', get_bloginfo('name'));
 | 
						|
        
 | 
						|
        // Enable debugging for failed sends
 | 
						|
        if (defined('WP_DEBUG') && WP_DEBUG) {
 | 
						|
            $phpmailer->SMTPDebug = 2;
 | 
						|
            $phpmailer->Debugoutput = 'error_log';
 | 
						|
        }
 | 
						|
    }
 | 
						|
    
 | 
						|
    /**
 | 
						|
     * Create email logs table if it doesn't exist
 | 
						|
     */
 | 
						|
    private static function create_email_logs_table() {
 | 
						|
        global $wpdb;
 | 
						|
        
 | 
						|
        $table_name = $wpdb->prefix . 'wpdd_email_logs';
 | 
						|
        $charset_collate = $wpdb->get_charset_collate();
 | 
						|
        
 | 
						|
        $sql = "CREATE TABLE IF NOT EXISTS $table_name (
 | 
						|
            id bigint(20) NOT NULL AUTO_INCREMENT,
 | 
						|
            to_email varchar(100) NOT NULL,
 | 
						|
            subject varchar(255) NOT NULL,
 | 
						|
            message longtext NOT NULL,
 | 
						|
            status varchar(20) NOT NULL DEFAULT 'sent',
 | 
						|
            email_type varchar(50) DEFAULT 'general',
 | 
						|
            error_message text DEFAULT NULL,
 | 
						|
            sent_at datetime DEFAULT CURRENT_TIMESTAMP,
 | 
						|
            PRIMARY KEY (id),
 | 
						|
            KEY to_email (to_email),
 | 
						|
            KEY status (status),
 | 
						|
            KEY email_type (email_type),
 | 
						|
            KEY sent_at (sent_at)
 | 
						|
        ) $charset_collate;";
 | 
						|
        
 | 
						|
        require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
 | 
						|
        dbDelta($sql);
 | 
						|
    }
 | 
						|
    
 | 
						|
    /**
 | 
						|
     * Send order confirmation email
 | 
						|
     */
 | 
						|
    public static function send_order_confirmation($order_id) {
 | 
						|
        global $wpdb;
 | 
						|
        
 | 
						|
        $order = $wpdb->get_row($wpdb->prepare(
 | 
						|
            "SELECT * FROM {$wpdb->prefix}wpdd_orders WHERE id = %d",
 | 
						|
            $order_id
 | 
						|
        ));
 | 
						|
        
 | 
						|
        if (!$order) {
 | 
						|
            return false;
 | 
						|
        }
 | 
						|
        
 | 
						|
        $product = get_post($order->product_id);
 | 
						|
        if (!$product) {
 | 
						|
            return false;
 | 
						|
        }
 | 
						|
        
 | 
						|
        $subject = sprintf(__('Order Confirmation - %s', 'wp-digital-download'), $product->post_title);
 | 
						|
        
 | 
						|
        $message = sprintf(
 | 
						|
            __('<h2>Thank you for your purchase!</h2>
 | 
						|
            <p>Your order has been confirmed.</p>
 | 
						|
            <h3>Order Details:</h3>
 | 
						|
            <ul>
 | 
						|
                <li><strong>Order ID:</strong> #%d</li>
 | 
						|
                <li><strong>Product:</strong> %s</li>
 | 
						|
                <li><strong>Amount:</strong> %s</li>
 | 
						|
                <li><strong>Date:</strong> %s</li>
 | 
						|
            </ul>
 | 
						|
            <p>You can download your purchase from your account page.</p>
 | 
						|
            <p>Thank you for your business!</p>', 'wp-digital-download'),
 | 
						|
            $order->id,
 | 
						|
            esc_html($product->post_title),
 | 
						|
            wpdd_format_price($order->amount, $order->currency),
 | 
						|
            $order->purchase_date
 | 
						|
        );
 | 
						|
        
 | 
						|
        return self::send($order->customer_email, $subject, $message, 'order_confirmation');
 | 
						|
    }
 | 
						|
    
 | 
						|
    /**
 | 
						|
     * Send download link email
 | 
						|
     */
 | 
						|
    public static function send_download_link($order_id, $download_link) {
 | 
						|
        global $wpdb;
 | 
						|
        
 | 
						|
        $order = $wpdb->get_row($wpdb->prepare(
 | 
						|
            "SELECT * FROM {$wpdb->prefix}wpdd_orders WHERE id = %d",
 | 
						|
            $order_id
 | 
						|
        ));
 | 
						|
        
 | 
						|
        if (!$order) {
 | 
						|
            return false;
 | 
						|
        }
 | 
						|
        
 | 
						|
        $product = get_post($order->product_id);
 | 
						|
        if (!$product) {
 | 
						|
            return false;
 | 
						|
        }
 | 
						|
        
 | 
						|
        $subject = sprintf(__('Your Download Link - %s', 'wp-digital-download'), $product->post_title);
 | 
						|
        
 | 
						|
        $message = sprintf(
 | 
						|
            __('<h2>Your Download is Ready!</h2>
 | 
						|
            <p>Click the link below to download your purchase:</p>
 | 
						|
            <p><a href="%s" style="display: inline-block; padding: 10px 20px; background: #0073aa; color: white; text-decoration: none; border-radius: 3px;">Download Now</a></p>
 | 
						|
            <h3>Product:</h3>
 | 
						|
            <p>%s</p>
 | 
						|
            <p><em>Note: This download link will expire. Please download your file as soon as possible.</em></p>
 | 
						|
            <p>Thank you!</p>', 'wp-digital-download'),
 | 
						|
            esc_url($download_link),
 | 
						|
            esc_html($product->post_title)
 | 
						|
        );
 | 
						|
        
 | 
						|
        return self::send($order->customer_email, $subject, $message, 'download_link');
 | 
						|
    }
 | 
						|
} |