admin_url('admin-ajax.php'), 'nonce' => wp_create_nonce('wpdd_payouts'), 'confirm_payout' => __('Are you sure you want to process this payout?', 'wp-digital-download'), 'confirm_bulk' => __('Are you sure you want to process all selected payouts?', 'wp-digital-download') )); } public static function render_page() { global $wpdb; // Get filter parameters $status_filter = isset($_GET['status']) ? sanitize_text_field($_GET['status']) : 'pending'; $creator_filter = isset($_GET['creator']) ? intval($_GET['creator']) : 0; // Get creators with balance $creators = WPDD_Creator::get_creators_with_balance(); $currency = get_option('wpdd_currency', 'USD'); $threshold = floatval(get_option('wpdd_payout_threshold', 0)); // Get payout requests (requested status) $payout_requests = $wpdb->get_results( "SELECT p.*, u.display_name, u.user_email FROM {$wpdb->prefix}wpdd_payouts p INNER JOIN {$wpdb->users} u ON p.creator_id = u.ID WHERE p.status = 'requested' ORDER BY p.created_at ASC" ); // Get payout history $query = "SELECT p.*, u.display_name, u.user_email FROM {$wpdb->prefix}wpdd_payouts p INNER JOIN {$wpdb->users} u ON p.creator_id = u.ID WHERE 1=1"; if ($status_filter && $status_filter !== 'all') { $query .= $wpdb->prepare(" AND p.status = %s", $status_filter); } if ($creator_filter) { $query .= $wpdb->prepare(" AND p.creator_id = %d", $creator_filter); } $query .= " ORDER BY p.created_at DESC LIMIT 100"; $payouts = $wpdb->get_results($query); ?>

' . esc_html($error_detail) . '' : __('Unknown error occurred. Please try again.', 'wp-digital-download'); ?>

()

display_name); ?>
user_email); ?>
amount, $request->currency); ?> paypal_email); ?> created_at))); ?>
id, 'wpdd_nonce'); ?>
id, 'wpdd_nonce'); ?>

ID); $net_earnings = WPDD_Creator::get_creator_net_earnings($creator->ID); $can_payout = !empty($creator->paypal_email) && floatval($creator->balance) > 0; $auto_eligible = $threshold > 0 && floatval($creator->balance) >= $threshold; ?> >
display_name); ?>
user_email); ?>
paypal_email)) : ?> paypal_email); ?> balance, $currency); ?>
ID, 'wpdd_nonce'); ?>
0) : ?>

processed_by ? get_userdata($payout->processed_by) : null; ?>
created_at))); ?> processed_at) : ?>
processed_at))); ?>
display_name); ?>
user_email); ?>
amount, $payout->currency); ?> paypal_email); ?> transaction_id ?: '-'); ?> notes) : ?>
notes); ?>
status) { case 'completed': $status_class = 'notice-success'; break; case 'failed': $status_class = 'notice-error'; break; case 'pending': $status_class = 'notice-warning'; break; } ?> status)); ?> payout_method)); ?> display_name); ?> payout_method === 'automatic' ? __('System', 'wp-digital-download') : '-'; ?>

0) { $creators = WPDD_Creator::get_creators_with_balance(); foreach ($creators as $creator) { if (floatval($creator->balance) >= $threshold && !empty($creator->paypal_email)) { self::create_payout($creator->ID); } } } } else { // Process selected creators $creator_ids = isset($_POST['creator_ids']) ? array_map('intval', $_POST['creator_ids']) : array(); foreach ($creator_ids as $creator_id) { self::create_payout($creator_id); } } wp_redirect(admin_url('edit.php?post_type=wpdd_product&page=wpdd-payouts&message=success')); exit; } public static function create_payout($creator_id, $method = 'manual') { global $wpdb; // Validate creator $creator = get_userdata($creator_id); if (!$creator) { return array('success' => false, 'error' => 'Creator not found'); } $balance = WPDD_Creator::get_creator_balance($creator_id); $paypal_email = get_user_meta($creator_id, 'wpdd_paypal_email', true); if ($balance <= 0) { return array('success' => false, 'error' => 'Creator has zero balance to payout'); } if (empty($paypal_email)) { return array('success' => false, 'error' => 'Creator has no PayPal email configured'); } // Validate PayPal credentials are configured $client_id = get_option('wpdd_paypal_client_id'); $secret = get_option('wpdd_paypal_secret'); if (empty($client_id) || empty($secret)) { return array('success' => false, 'error' => 'PayPal credentials not configured in settings'); } $currency = get_option('wpdd_currency', 'USD'); $current_user_id = get_current_user_id(); // Create payout record $wpdb->insert( $wpdb->prefix . 'wpdd_payouts', array( 'creator_id' => $creator_id, 'amount' => $balance, 'currency' => $currency, 'paypal_email' => $paypal_email, 'status' => 'pending', 'payout_method' => $method, 'processed_by' => $current_user_id, 'created_at' => current_time('mysql') ), array('%d', '%f', '%s', '%s', '%s', '%s', '%d', '%s') ); $payout_id = $wpdb->insert_id; if (!$payout_id) { return array('success' => false, 'error' => 'Failed to create payout record in database'); } // Try to process via PayPal API $result = WPDD_PayPal_Payouts::process_payout($payout_id); if ($result['success']) { // Update payout status $wpdb->update( $wpdb->prefix . 'wpdd_payouts', array( 'status' => 'completed', 'transaction_id' => $result['transaction_id'], 'processed_at' => current_time('mysql') ), array('id' => $payout_id), array('%s', '%s', '%s'), array('%d') ); // Mark all available earnings for this creator as paid $wpdb->update( $wpdb->prefix . 'wpdd_creator_earnings', array( 'payout_id' => $payout_id, 'payout_status' => 'paid' ), array( 'creator_id' => $creator_id, 'payout_status' => 'available' ), array('%d', '%s'), array('%d', '%s') ); // Reset creator balance update_user_meta($creator_id, 'wpdd_creator_balance', 0); return array('success' => true, 'message' => 'Payout processed successfully'); } else { // Update with error $wpdb->update( $wpdb->prefix . 'wpdd_payouts', array( 'status' => 'failed', 'notes' => $result['error'] ), array('id' => $payout_id), array('%s', '%s'), array('%d') ); return array('success' => false, 'error' => $result['error'] ?? 'PayPal payout processing failed'); } } public static function process_payout_request() { if (!current_user_can('manage_options')) { wp_die(__('You do not have permission to perform this action.', 'wp-digital-download')); } $payout_id = isset($_POST['payout_id']) ? intval($_POST['payout_id']) : 0; if (!$payout_id || !wp_verify_nonce($_POST['wpdd_nonce'], 'wpdd_process_payout_request_' . $payout_id)) { wp_redirect(admin_url('edit.php?post_type=wpdd_product&page=wpdd-payouts&message=error')); exit; } global $wpdb; // Get the payout request $payout = $wpdb->get_row($wpdb->prepare( "SELECT * FROM {$wpdb->prefix}wpdd_payouts WHERE id = %d AND status = 'requested'", $payout_id )); if (!$payout) { wp_redirect(admin_url('edit.php?post_type=wpdd_product&page=wpdd-payouts&message=error')); exit; } // Process via PayPal API $result = WPDD_PayPal_Payouts::process_payout($payout_id); if ($result['success']) { // Update payout status $wpdb->update( $wpdb->prefix . 'wpdd_payouts', array( 'status' => 'completed', 'transaction_id' => $result['transaction_id'], 'processed_by' => get_current_user_id(), 'processed_at' => current_time('mysql') ), array('id' => $payout_id), array('%s', '%s', '%d', '%s'), array('%d') ); wp_redirect(admin_url('edit.php?post_type=wpdd_product&page=wpdd-payouts&message=success')); } else { // Update with error $wpdb->update( $wpdb->prefix . 'wpdd_payouts', array( 'status' => 'failed', 'notes' => $result['error'] ), array('id' => $payout_id), array('%s', '%s'), array('%d') ); wp_redirect(admin_url('edit.php?post_type=wpdd_product&page=wpdd-payouts&message=error')); } exit; } public static function reject_payout_request() { if (!current_user_can('manage_options')) { wp_die(__('You do not have permission to perform this action.', 'wp-digital-download')); } $payout_id = isset($_POST['payout_id']) ? intval($_POST['payout_id']) : 0; if (!$payout_id || !wp_verify_nonce($_POST['wpdd_nonce'], 'wpdd_reject_payout_request_' . $payout_id)) { wp_redirect(admin_url('edit.php?post_type=wpdd_product&page=wpdd-payouts&message=error')); exit; } global $wpdb; // Get the payout request $payout = $wpdb->get_row($wpdb->prepare( "SELECT * FROM {$wpdb->prefix}wpdd_payouts WHERE id = %d AND status = 'requested'", $payout_id )); if (!$payout) { wp_redirect(admin_url('edit.php?post_type=wpdd_product&page=wpdd-payouts&message=error')); exit; } // Update status to failed/rejected $wpdb->update( $wpdb->prefix . 'wpdd_payouts', array( 'status' => 'failed', 'notes' => 'Request rejected by administrator', 'processed_by' => get_current_user_id(), 'processed_at' => current_time('mysql') ), array('id' => $payout_id), array('%s', '%s', '%d', '%s'), array('%d') ); // Restore balance to creator update_user_meta($payout->creator_id, 'wpdd_creator_balance', $payout->amount); wp_redirect(admin_url('edit.php?post_type=wpdd_product&page=wpdd-payouts&message=success')); exit; } public static function process_manual_payout() { if (!current_user_can('manage_options') || !wp_verify_nonce($_POST['wpdd_nonce'], 'wpdd_manual_payout')) { wp_die(__('Security check failed', 'wp-digital-download')); } $creator_id = intval($_POST['creator_id']); $amount = floatval($_POST['payout_amount']); $reason = sanitize_textarea_field($_POST['payout_reason']); if (!$creator_id || $amount <= 0) { wp_redirect(add_query_arg('message', 'error', wp_get_referer())); exit; } $creator = get_userdata($creator_id); if (!$creator || !in_array('wpdd_creator', $creator->roles)) { wp_redirect(add_query_arg('message', 'error', wp_get_referer())); exit; } $paypal_email = get_user_meta($creator_id, 'wpdd_paypal_email', true); if (empty($paypal_email)) { wp_redirect(add_query_arg('message', 'error', wp_get_referer())); exit; } global $wpdb; // Create the payout record $result = $wpdb->insert( $wpdb->prefix . 'wpdd_payouts', array( 'creator_id' => $creator_id, 'amount' => $amount, 'currency' => get_option('wpdd_currency', 'USD'), 'paypal_email' => $paypal_email, 'status' => 'pending', 'payout_method' => 'manual', 'notes' => $reason, 'created_at' => current_time('mysql'), 'processed_by' => get_current_user_id() ), array('%d', '%f', '%s', '%s', '%s', '%s', '%s', '%s', '%d') ); if (!$result) { wp_redirect(add_query_arg('message', 'error', wp_get_referer())); exit; } $payout_id = $wpdb->insert_id; // Try to process via PayPal if (class_exists('WPDD_PayPal_Payouts')) { $paypal_result = WPDD_PayPal_Payouts::process_payout($payout_id); if (!$paypal_result) { // Update status to failed $wpdb->update( $wpdb->prefix . 'wpdd_payouts', array('status' => 'failed'), array('id' => $payout_id), array('%s'), array('%d') ); } } wp_redirect(add_query_arg('message', 'success', wp_get_referer())); exit; } public static function adjust_creator_balance() { if (!current_user_can('manage_options') || !wp_verify_nonce($_POST['wpdd_nonce'], 'wpdd_adjust_balance')) { wp_die(__('Security check failed', 'wp-digital-download')); } $creator_id = intval($_POST['creator_id']); $adjustment_type = sanitize_text_field($_POST['adjustment_type']); $amount = floatval($_POST['adjustment_amount']); $reason = sanitize_textarea_field($_POST['adjustment_reason']); if (!$creator_id || $amount <= 0 || !in_array($adjustment_type, array('add', 'subtract'))) { wp_redirect(add_query_arg('message', 'error', wp_get_referer())); exit; } $creator = get_userdata($creator_id); if (!$creator || !in_array('wpdd_creator', $creator->roles)) { wp_redirect(add_query_arg('message', 'error', wp_get_referer())); exit; } // Get current balance $current_balance = floatval(get_user_meta($creator_id, 'wpdd_creator_balance', true)); // Calculate new balance if ($adjustment_type === 'add') { $new_balance = $current_balance + $amount; } else { $new_balance = max(0, $current_balance - $amount); // Don't allow negative balance } // Update the balance update_user_meta($creator_id, 'wpdd_creator_balance', $new_balance); // Create a record of this adjustment global $wpdb; $wpdb->insert( $wpdb->prefix . 'wpdd_balance_adjustments', array( 'creator_id' => $creator_id, 'adjustment_type' => $adjustment_type, 'amount' => $amount, 'previous_balance' => $current_balance, 'new_balance' => $new_balance, 'reason' => $reason, 'adjusted_by' => get_current_user_id(), 'created_at' => current_time('mysql') ), array('%d', '%s', '%f', '%f', '%f', '%s', '%d', '%s') ); wp_redirect(add_query_arg('message', 'balance_adjusted', wp_get_referer())); exit; } }