post_type !== 'wpdd_product') { wp_send_json_error(__('Product not found.', 'wp-digital-download')); } // IMPORTANT: Always check the actual database values, never trust client input $is_free = get_post_meta($product_id, '_wpdd_is_free', true); $price = get_post_meta($product_id, '_wpdd_price', true); $sale_price = get_post_meta($product_id, '_wpdd_sale_price', true); // Calculate actual price $actual_price = ($sale_price && $sale_price < $price) ? $sale_price : $price; // Security check: Verify this is actually a free product if (!$is_free && $actual_price > 0) { // Log potential security breach attempt error_log('WPDD Security: Attempted to download paid product ' . $product_id . ' as free from IP: ' . $_SERVER['REMOTE_ADDR']); wp_send_json_error(__('This product is not available for free download.', 'wp-digital-download')); } $customer_data = array( 'email' => sanitize_email($_POST['customer_email'] ?? ''), 'name' => sanitize_text_field($_POST['customer_name'] ?? '') ); if (!is_user_logged_in() && empty($customer_data['email'])) { wp_send_json_error(__('Please provide your email address.', 'wp-digital-download')); } // Create account if requested if (!is_user_logged_in() && isset($_POST['create_account']) && $_POST['create_account'] == '1') { $user_id = wp_create_user( $customer_data['email'], wp_generate_password(), $customer_data['email'] ); if (!is_wp_error($user_id)) { wp_update_user(array( 'ID' => $user_id, 'display_name' => $customer_data['name'], 'first_name' => $customer_data['name'] )); // Set customer role (remove default role first) $user = new WP_User($user_id); $user->remove_role('subscriber'); // Remove default WordPress role $user->add_role('wpdd_customer'); // Send new account email wp_new_user_notification($user_id, null, 'user'); // Log them in wp_set_current_user($user_id); wp_set_auth_cookie($user_id); } } $order_id = WPDD_Orders::create_order($product_id, $customer_data, 'free'); if ($order_id) { $order = WPDD_Orders::get_order($order_id); wp_send_json_success(array( 'redirect_url' => add_query_arg( 'order_id', $order->order_number, get_permalink(get_option('wpdd_thank_you_page_id')) ) )); } else { wp_send_json_error(__('Failed to process download. Please try again.', 'wp-digital-download')); } } public static function add_to_cart() { check_ajax_referer('wpdd-ajax-nonce', 'nonce'); $product_id = isset($_POST['product_id']) ? intval($_POST['product_id']) : 0; if (!$product_id) { wp_send_json_error(__('Invalid product.', 'wp-digital-download')); } $product = get_post($product_id); if (!$product || $product->post_type !== 'wpdd_product') { wp_send_json_error(__('Product not found.', 'wp-digital-download')); } if (!isset($_SESSION['wpdd_cart'])) { $_SESSION['wpdd_cart'] = array(); } if (in_array($product_id, $_SESSION['wpdd_cart'])) { wp_send_json_error(__('Product already in cart.', 'wp-digital-download')); } $_SESSION['wpdd_cart'][] = $product_id; wp_send_json_success(array( 'message' => __('Product added to cart.', 'wp-digital-download'), 'cart_count' => count($_SESSION['wpdd_cart']), 'checkout_url' => add_query_arg( 'product_id', $product_id, get_permalink(get_option('wpdd_checkout_page_id')) ) )); } public static function get_product_details() { check_ajax_referer('wpdd-ajax-nonce', 'nonce'); $product_id = isset($_POST['product_id']) ? intval($_POST['product_id']) : 0; if (!$product_id) { wp_send_json_error(__('Invalid product.', 'wp-digital-download')); } $product = get_post($product_id); if (!$product || $product->post_type !== 'wpdd_product') { wp_send_json_error(__('Product not found.', 'wp-digital-download')); } $price = get_post_meta($product_id, '_wpdd_price', true); $sale_price = get_post_meta($product_id, '_wpdd_sale_price', true); $is_free = get_post_meta($product_id, '_wpdd_is_free', true); $files = get_post_meta($product_id, '_wpdd_files', true); $download_limit = get_post_meta($product_id, '_wpdd_download_limit', true); $download_expiry = get_post_meta($product_id, '_wpdd_download_expiry', true); $creator = get_userdata($product->post_author); $data = array( 'id' => $product_id, 'title' => $product->post_title, 'description' => $product->post_content, 'excerpt' => $product->post_excerpt, 'price' => $price, 'sale_price' => $sale_price, 'is_free' => $is_free, 'final_price' => $is_free ? 0 : (($sale_price && $sale_price < $price) ? $sale_price : $price), 'creator' => array( 'id' => $creator->ID, 'name' => $creator->display_name, 'avatar' => get_avatar_url($creator->ID) ), 'files_count' => is_array($files) ? count($files) : 0, 'download_limit' => $download_limit ?: __('Unlimited', 'wp-digital-download'), 'download_expiry' => $download_expiry ? sprintf(__('%d days', 'wp-digital-download'), $download_expiry) : __('Never expires', 'wp-digital-download'), 'thumbnail' => get_the_post_thumbnail_url($product_id, 'full'), 'categories' => wp_get_post_terms($product_id, 'wpdd_product_category', array('fields' => 'names')), 'tags' => wp_get_post_terms($product_id, 'wpdd_product_tag', array('fields' => 'names')) ); if (is_user_logged_in()) { $current_user = wp_get_current_user(); $data['can_download'] = WPDD_Customer::can_download_product($current_user->ID, $product_id); } wp_send_json_success($data); } public static function check_download_status() { check_ajax_referer('wpdd-ajax-nonce', 'nonce'); if (!is_user_logged_in()) { wp_send_json_error(__('Please login to check download status.', 'wp-digital-download')); } $product_id = isset($_POST['product_id']) ? intval($_POST['product_id']) : 0; if (!$product_id) { wp_send_json_error(__('Invalid product.', 'wp-digital-download')); } $current_user = wp_get_current_user(); global $wpdb; $order = $wpdb->get_row($wpdb->prepare( "SELECT * FROM {$wpdb->prefix}wpdd_orders WHERE customer_id = %d AND product_id = %d AND status = 'completed' ORDER BY purchase_date DESC LIMIT 1", $current_user->ID, $product_id )); if (!$order) { wp_send_json_success(array( 'has_purchased' => false, 'message' => __('You have not purchased this product.', 'wp-digital-download') )); } $download_limit = get_post_meta($product_id, '_wpdd_download_limit', true); $download_expiry = get_post_meta($product_id, '_wpdd_download_expiry', true); $can_download = true; $message = ''; 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) { $can_download = false; $message = __('Your download period has expired.', 'wp-digital-download'); } } if ($can_download && $download_limit > 0 && $order->download_count >= $download_limit) { $can_download = false; $message = __('You have reached the download limit.', 'wp-digital-download'); } wp_send_json_success(array( 'has_purchased' => true, 'can_download' => $can_download, 'download_count' => $order->download_count, 'download_limit' => $download_limit ?: 0, 'purchase_date' => $order->purchase_date, 'message' => $message ?: __('You can download this product.', 'wp-digital-download'), 'download_url' => $can_download ? wp_nonce_url( add_query_arg(array('wpdd_download' => $order->id)), 'wpdd_download_' . $order->id ) : '' )); } public static function move_to_protected() { check_ajax_referer('wpdd-admin-nonce', 'nonce'); if (!current_user_can('edit_wpdd_products')) { wp_send_json_error(__('You do not have permission to perform this action.', 'wp-digital-download')); } $attachment_id = isset($_POST['attachment_id']) ? intval($_POST['attachment_id']) : 0; if (!$attachment_id) { wp_send_json_error(__('Invalid attachment ID.', 'wp-digital-download')); } $file_path = get_attached_file($attachment_id); if (!$file_path || !file_exists($file_path)) { wp_send_json_error(__('File not found.', 'wp-digital-download')); } // Create protected directory if it doesn't exist $upload_dir = wp_upload_dir(); $protected_dir = trailingslashit($upload_dir['basedir']) . WPDD_UPLOADS_DIR; if (!file_exists($protected_dir)) { wp_mkdir_p($protected_dir); // Add .htaccess protection $htaccess_content = "Options -Indexes\ndeny from all\n"; file_put_contents($protected_dir . '/.htaccess', $htaccess_content); // Add index.php protection $index_content = " home_url('?wpdd_file_download=' . $attachment_id . '&token=' . $token), 'protected_path' => $new_file_path, 'message' => __('File moved to protected directory.', 'wp-digital-download') )); } else { wp_send_json_error(__('Failed to move file to protected directory.', 'wp-digital-download')); } } public static function upload_protected_file() { check_ajax_referer('wpdd-admin-nonce', 'nonce'); if (!current_user_can('edit_wpdd_products')) { wp_send_json_error(__('You do not have permission to upload files.', 'wp-digital-download')); } if (!isset($_FILES['file'])) { wp_send_json_error(__('No file uploaded.', 'wp-digital-download')); } $uploaded_file = $_FILES['file']; // Check for upload errors if ($uploaded_file['error'] !== UPLOAD_ERR_OK) { wp_send_json_error(__('Upload failed.', 'wp-digital-download')); } // Validate file type $allowed_types = array( 'pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'zip', 'rar', '7z', 'tar', 'gz', 'jpg', 'jpeg', 'png', 'gif', 'svg', 'webp', 'mp3', 'wav', 'flac', 'aac', 'ogg', 'mp4', 'avi', 'mkv', 'mov', 'wmv', 'txt', 'rtf', 'epub', 'mobi' ); $file_ext = strtolower(pathinfo($uploaded_file['name'], PATHINFO_EXTENSION)); if (!in_array($file_ext, $allowed_types)) { wp_send_json_error(__('File type not allowed.', 'wp-digital-download')); } // Create protected directory structure $upload_dir = wp_upload_dir(); $protected_dir = trailingslashit($upload_dir['basedir']) . WPDD_UPLOADS_DIR; if (!file_exists($protected_dir)) { wp_mkdir_p($protected_dir); // Add .htaccess protection $htaccess_content = "Options -Indexes\ndeny from all\n"; file_put_contents($protected_dir . '/.htaccess', $htaccess_content); // Add index.php protection $index_content = " $file_path, 'file_name' => $unique_filename, 'original_name' => $uploaded_file['name'], 'file_size' => filesize($file_path), 'file_type' => $uploaded_file['type'], 'upload_date' => current_time('mysql'), 'token' => $token ); // Store in options table (in production, consider custom table) update_option('wpdd_protected_file_' . $file_id, $file_meta); wp_send_json_success(array( 'protected_url' => home_url('?wpdd_protected_download=' . $file_id . '&token=' . $token), 'file_id' => $file_id, 'file_name' => $unique_filename, 'file_size' => size_format($file_meta['file_size']), 'message' => __('File uploaded successfully to protected directory.', 'wp-digital-download') )); } else { wp_send_json_error(__('Failed to save uploaded file.', 'wp-digital-download')); } } /** * Handle password change for customers */ public static function change_password() { check_ajax_referer('wpdd_change_password', 'nonce'); if (!is_user_logged_in()) { wp_send_json_error(__('You must be logged in to change your password.', 'wp-digital-download')); } $current_user = wp_get_current_user(); // Only allow customers to change their own password this way if (!in_array('wpdd_customer', $current_user->roles)) { wp_send_json_error(__('This function is only available for customers.', 'wp-digital-download')); } $current_password = sanitize_text_field($_POST['current_password'] ?? ''); $new_password = sanitize_text_field($_POST['new_password'] ?? ''); $confirm_password = sanitize_text_field($_POST['confirm_password'] ?? ''); if (empty($current_password) || empty($new_password) || empty($confirm_password)) { wp_send_json_error(__('All password fields are required.', 'wp-digital-download')); } if ($new_password !== $confirm_password) { wp_send_json_error(__('New passwords do not match.', 'wp-digital-download')); } if (strlen($new_password) < 8) { wp_send_json_error(__('New password must be at least 8 characters long.', 'wp-digital-download')); } // Verify current password if (!wp_check_password($current_password, $current_user->user_pass, $current_user->ID)) { wp_send_json_error(__('Current password is incorrect.', 'wp-digital-download')); } // Update password $result = wp_update_user(array( 'ID' => $current_user->ID, 'user_pass' => $new_password )); if (is_wp_error($result)) { wp_send_json_error(__('Failed to update password. Please try again.', 'wp-digital-download')); } // Re-authenticate user to prevent logout wp_set_current_user($current_user->ID); wp_set_auth_cookie($current_user->ID); wp_send_json_success(__('Password changed successfully!', 'wp-digital-download')); } }