get_row($wpdb->prepare( "SELECT * FROM {$wpdb->prefix}wpdd_orders WHERE id = %d", $order_id )); if (!$order) { error_log('WPDD License Debug: Order not found for ID: ' . $order_id); return; } // Check if product is software license type $product_type = get_post_meta($order->product_id, '_wpdd_product_type', true); error_log('WPDD License Debug: Product type for product ' . $order->product_id . ': ' . $product_type); if ($product_type !== 'software_license') { error_log('WPDD License Debug: Product type is not software_license, skipping license generation'); return; } // Check if license already exists for this order $existing = $wpdb->get_var($wpdb->prepare( "SELECT id FROM {$wpdb->prefix}wpdd_licenses WHERE order_id = %d", $order_id )); if ($existing) { error_log('WPDD License Debug: License already exists for order ' . $order_id . ', license ID: ' . $existing); return; } error_log('WPDD License Debug: Generating new license for order ' . $order_id); // Generate unique license key $license_key = self::generate_license_key(); // Ensure it's unique while (self::license_key_exists($license_key)) { $license_key = self::generate_license_key(); } // Get license settings from product $max_activations = get_post_meta($order->product_id, '_wpdd_max_activations', true) ?: 1; $license_duration = get_post_meta($order->product_id, '_wpdd_license_duration', true); // in days $expires_at = null; if ($license_duration && $license_duration > 0) { $expires_at = date('Y-m-d H:i:s', strtotime("+{$license_duration} days")); } // Insert license $wpdb->insert( $wpdb->prefix . 'wpdd_licenses', array( 'license_key' => $license_key, 'product_id' => $order->product_id, 'order_id' => $order_id, 'customer_id' => $order->customer_id, 'customer_email' => $order->customer_email, 'status' => 'active', 'max_activations' => $max_activations, 'expires_at' => $expires_at, 'created_at' => current_time('mysql') ), array('%s', '%d', '%d', '%d', '%s', '%s', '%d', '%s', '%s') ); if ($wpdb->insert_id) { error_log('WPDD License Debug: License created successfully with ID: ' . $wpdb->insert_id . ', license key: ' . $license_key); } else { error_log('WPDD License Debug: Failed to create license. Last error: ' . $wpdb->last_error); } // Send license key to customer self::send_license_email($order, $license_key); return $license_key; } /** * Check if license key exists */ public static function license_key_exists($license_key) { global $wpdb; return $wpdb->get_var($wpdb->prepare( "SELECT COUNT(*) FROM {$wpdb->prefix}wpdd_licenses WHERE license_key = %s", $license_key )) > 0; } /** * Validate license key */ public static function validate_license($license_key, $product_slug = null, $site_url = null) { global $wpdb; // Get license details $license = $wpdb->get_row($wpdb->prepare( "SELECT l.*, p.post_name as product_slug FROM {$wpdb->prefix}wpdd_licenses l LEFT JOIN {$wpdb->prefix}posts p ON l.product_id = p.ID WHERE l.license_key = %s", $license_key )); if (!$license) { return array( 'valid' => false, 'error' => 'invalid_license', 'message' => __('Invalid license key.', 'wp-digital-download') ); } // Check product match if ($product_slug && $license->product_slug !== $product_slug) { return array( 'valid' => false, 'error' => 'product_mismatch', 'message' => __('License key is not valid for this product.', 'wp-digital-download') ); } // Check status if ($license->status !== 'active') { return array( 'valid' => false, 'error' => 'license_' . $license->status, 'message' => sprintf(__('License is %s.', 'wp-digital-download'), $license->status) ); } // Check expiration if ($license->expires_at && strtotime($license->expires_at) < time()) { // Update status to expired $wpdb->update( $wpdb->prefix . 'wpdd_licenses', array('status' => 'expired'), array('id' => $license->id), array('%s'), array('%d') ); return array( 'valid' => false, 'error' => 'license_expired', 'message' => __('License has expired.', 'wp-digital-download'), 'expired_at' => $license->expires_at ); } // Check activation limit if site_url provided if ($site_url) { $activation_count = $wpdb->get_var($wpdb->prepare( "SELECT COUNT(*) FROM {$wpdb->prefix}wpdd_license_activations WHERE license_id = %d AND status = 'active'", $license->id )); $is_activated = $wpdb->get_var($wpdb->prepare( "SELECT COUNT(*) FROM {$wpdb->prefix}wpdd_license_activations WHERE license_id = %d AND site_url = %s AND status = 'active'", $license->id, $site_url )); if (!$is_activated && $activation_count >= $license->max_activations) { return array( 'valid' => false, 'error' => 'activation_limit', 'message' => sprintf(__('License activation limit reached (%d/%d).', 'wp-digital-download'), $activation_count, $license->max_activations), 'activations' => $activation_count, 'max_activations' => $license->max_activations ); } } // Update last checked $wpdb->update( $wpdb->prefix . 'wpdd_licenses', array('last_checked' => current_time('mysql')), array('id' => $license->id), array('%s'), array('%d') ); return array( 'valid' => true, 'license' => $license, 'message' => __('License is valid.', 'wp-digital-download') ); } /** * Activate license for a site */ public static function activate_license($license_key, $site_url, $site_name = null, $wp_version = null, $php_version = null) { global $wpdb; // Validate license first $validation = self::validate_license($license_key, null, $site_url); if (!$validation['valid']) { return $validation; } $license = $validation['license']; // Check if already activated for this site $existing = $wpdb->get_row($wpdb->prepare( "SELECT * FROM {$wpdb->prefix}wpdd_license_activations WHERE license_id = %d AND site_url = %s", $license->id, $site_url )); if ($existing && $existing->status === 'active') { return array( 'success' => true, 'already_active' => true, 'message' => __('License already activated for this site.', 'wp-digital-download') ); } if ($existing) { // Reactivate $wpdb->update( $wpdb->prefix . 'wpdd_license_activations', array( 'status' => 'active', 'activated_at' => current_time('mysql'), 'last_checked' => current_time('mysql'), 'wp_version' => $wp_version, 'php_version' => $php_version, 'site_name' => $site_name ), array('id' => $existing->id), array('%s', '%s', '%s', '%s', '%s', '%s'), array('%d') ); } else { // New activation $wpdb->insert( $wpdb->prefix . 'wpdd_license_activations', array( 'license_id' => $license->id, 'license_key' => $license_key, 'site_url' => $site_url, 'site_name' => $site_name, 'activated_at' => current_time('mysql'), 'last_checked' => current_time('mysql'), 'wp_version' => $wp_version, 'php_version' => $php_version, 'status' => 'active' ), array('%d', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s') ); } // Update activation count $count = $wpdb->get_var($wpdb->prepare( "SELECT COUNT(*) FROM {$wpdb->prefix}wpdd_license_activations WHERE license_id = %d AND status = 'active'", $license->id )); $wpdb->update( $wpdb->prefix . 'wpdd_licenses', array('activations_count' => $count), array('id' => $license->id), array('%d'), array('%d') ); return array( 'success' => true, 'message' => __('License activated successfully.', 'wp-digital-download'), 'activations' => $count, 'max_activations' => $license->max_activations ); } /** * Deactivate license for a site */ public static function deactivate_license($license_key, $site_url) { global $wpdb; // Get license $license = $wpdb->get_row($wpdb->prepare( "SELECT * FROM {$wpdb->prefix}wpdd_licenses WHERE license_key = %s", $license_key )); if (!$license) { return array( 'success' => false, 'error' => 'invalid_license', 'message' => __('Invalid license key.', 'wp-digital-download') ); } // Deactivate $updated = $wpdb->update( $wpdb->prefix . 'wpdd_license_activations', array('status' => 'deactivated'), array( 'license_id' => $license->id, 'site_url' => $site_url ), array('%s'), array('%d', '%s') ); if (!$updated) { return array( 'success' => false, 'error' => 'not_activated', 'message' => __('License not activated for this site.', 'wp-digital-download') ); } // Update activation count $count = $wpdb->get_var($wpdb->prepare( "SELECT COUNT(*) FROM {$wpdb->prefix}wpdd_license_activations WHERE license_id = %d AND status = 'active'", $license->id )); $wpdb->update( $wpdb->prefix . 'wpdd_licenses', array('activations_count' => $count), array('id' => $license->id), array('%d'), array('%d') ); return array( 'success' => true, 'message' => __('License deactivated successfully.', 'wp-digital-download') ); } /** * Send license email to customer */ private static function send_license_email($order, $license_key) { $product = get_post($order->product_id); $subject = sprintf(__('Your License Key for %s', 'wp-digital-download'), $product->post_title); $message = sprintf( __("Hi %s,\n\nThank you for your purchase!\n\nHere is your license key for %s:\n\n%s\n\nPlease keep this key safe. You will need it to activate and receive updates for your software.\n\nBest regards,\n%s", 'wp-digital-download'), $order->customer_name ?: $order->customer_email, $product->post_title, $license_key, get_bloginfo('name') ); wp_mail($order->customer_email, $subject, $message); } /** * Get license details for admin */ public static function get_license_details($license_key) { global $wpdb; $license = $wpdb->get_row($wpdb->prepare( "SELECT l.*, p.post_title as product_name FROM {$wpdb->prefix}wpdd_licenses l LEFT JOIN {$wpdb->prefix}posts p ON l.product_id = p.ID WHERE l.license_key = %s", $license_key )); if (!$license) { return null; } // Get activations $license->activations = $wpdb->get_results($wpdb->prepare( "SELECT * FROM {$wpdb->prefix}wpdd_license_activations WHERE license_id = %d ORDER BY activated_at DESC", $license->id )); return $license; } }