Adding more functionality

This commit is contained in:
2025-08-29 18:54:14 -07:00
parent 264e65006a
commit ce48f1615f
14 changed files with 4098 additions and 84 deletions

View File

@@ -12,6 +12,7 @@ class WPDD_Admin {
add_action('manage_wpdd_product_posts_custom_column', array(__CLASS__, 'render_product_columns'), 10, 2);
add_filter('manage_edit-wpdd_product_sortable_columns', array(__CLASS__, 'make_columns_sortable'));
add_action('pre_get_posts', array(__CLASS__, 'sort_products_by_column'));
add_action('pre_get_posts', array(__CLASS__, 'filter_creator_products'));
add_action('admin_init', array(__CLASS__, 'handle_admin_actions'));
// Initialize admin payouts
@@ -21,41 +22,70 @@ class WPDD_Admin {
}
public static function add_admin_menus() {
add_submenu_page(
'edit.php?post_type=wpdd_product',
__('Orders', 'wp-digital-download'),
__('Orders', 'wp-digital-download'),
'wpdd_manage_orders',
'wpdd-orders',
array(__CLASS__, 'render_orders_page')
);
// Show different menus based on user role
$user = wp_get_current_user();
$is_creator = in_array('wpdd_creator', (array) $user->roles);
$is_admin = current_user_can('manage_options');
add_submenu_page(
'edit.php?post_type=wpdd_product',
__('Reports', 'wp-digital-download'),
__('Reports', 'wp-digital-download'),
'wpdd_view_reports',
'wpdd-reports',
array(__CLASS__, 'render_reports_page')
);
if ($is_admin) {
// Full admin menus
add_submenu_page(
'edit.php?post_type=wpdd_product',
__('Orders', 'wp-digital-download'),
__('Orders', 'wp-digital-download'),
'wpdd_manage_orders',
'wpdd-orders',
array(__CLASS__, 'render_orders_page')
);
add_submenu_page(
'edit.php?post_type=wpdd_product',
__('Reports', 'wp-digital-download'),
__('Reports', 'wp-digital-download'),
'wpdd_view_reports',
'wpdd-reports',
array(__CLASS__, 'render_reports_page')
);
add_submenu_page(
'edit.php?post_type=wpdd_product',
__('Customers', 'wp-digital-download'),
__('Customers', 'wp-digital-download'),
'wpdd_manage_orders',
'wpdd-customers',
array(__CLASS__, 'render_customers_page')
);
add_submenu_page(
'edit.php?post_type=wpdd_product',
__('Shortcodes', 'wp-digital-download'),
__('Shortcodes', 'wp-digital-download'),
'edit_wpdd_products',
'wpdd-shortcodes',
array(__CLASS__, 'render_shortcodes_page')
);
}
add_submenu_page(
'edit.php?post_type=wpdd_product',
__('Customers', 'wp-digital-download'),
__('Customers', 'wp-digital-download'),
'wpdd_manage_orders',
'wpdd-customers',
array(__CLASS__, 'render_customers_page')
);
add_submenu_page(
'edit.php?post_type=wpdd_product',
__('Shortcodes', 'wp-digital-download'),
__('Shortcodes', 'wp-digital-download'),
'edit_wpdd_products',
'wpdd-shortcodes',
array(__CLASS__, 'render_shortcodes_page')
);
if ($is_creator || $is_admin) {
// Creator-specific menus
add_submenu_page(
'edit.php?post_type=wpdd_product',
__('My Sales', 'wp-digital-download'),
__('My Sales', 'wp-digital-download'),
'wpdd_view_own_sales',
'wpdd-creator-sales',
array(__CLASS__, 'render_creator_sales_page')
);
add_submenu_page(
'edit.php?post_type=wpdd_product',
__('My Payouts', 'wp-digital-download'),
__('My Payouts', 'wp-digital-download'),
'wpdd_view_own_sales',
'wpdd-creator-payouts',
array(__CLASS__, 'render_creator_payouts_page')
);
}
}
public static function add_product_columns($columns) {
@@ -917,4 +947,289 @@ class WPDD_Admin {
<?php
}
public static function filter_creator_products($query) {
if (!is_admin() || !$query->is_main_query()) {
return;
}
if (!isset($_GET['post_type']) || $_GET['post_type'] !== 'wpdd_product') {
return;
}
$user = wp_get_current_user();
$is_creator = in_array('wpdd_creator', (array) $user->roles);
$is_admin = current_user_can('manage_options');
// Only filter for creators, not admins
if ($is_creator && !$is_admin) {
$query->set('author', get_current_user_id());
}
}
public static function render_creator_sales_page() {
global $wpdb;
$user_id = get_current_user_id();
$currency = get_option('wpdd_currency', 'USD');
$commission_rate = floatval(get_option('wpdd_commission_rate', 0));
// Get creator's sales data
$sales = $wpdb->get_results($wpdb->prepare(
"SELECT o.*, p.post_title as product_name,
(o.total * %f / 100) as platform_fee,
(o.total * (100 - %f) / 100) as creator_earning
FROM {$wpdb->prefix}wpdd_orders o
INNER JOIN {$wpdb->posts} p ON o.product_id = p.ID
WHERE p.post_author = %d
AND o.status = 'completed'
ORDER BY o.purchase_date DESC
LIMIT 100",
$commission_rate,
$commission_rate,
$user_id
));
// Get totals
$total_sales = $wpdb->get_var($wpdb->prepare(
"SELECT SUM(o.total)
FROM {$wpdb->prefix}wpdd_orders o
INNER JOIN {$wpdb->posts} p ON o.product_id = p.ID
WHERE p.post_author = %d
AND o.status = 'completed'",
$user_id
));
$total_earnings = $total_sales * (1 - ($commission_rate / 100));
$current_balance = WPDD_Creator::get_creator_balance($user_id);
?>
<div class="wrap">
<h1><?php _e('My Sales Report', 'wp-digital-download'); ?></h1>
<div class="wpdd-stats-row" style="display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 20px; margin-bottom: 30px;">
<div class="wpdd-stat-card" style="background: #fff; padding: 20px; border: 1px solid #ccd0d4; border-radius: 4px;">
<h3 style="margin: 0 0 10px; color: #646970;"><?php _e('Total Sales', 'wp-digital-download'); ?></h3>
<div style="font-size: 24px; font-weight: bold; color: #1d2327;"><?php echo wpdd_format_price($total_sales, $currency); ?></div>
</div>
<div class="wpdd-stat-card" style="background: #fff; padding: 20px; border: 1px solid #ccd0d4; border-radius: 4px;">
<h3 style="margin: 0 0 10px; color: #646970;"><?php _e('Your Earnings', 'wp-digital-download'); ?></h3>
<div style="font-size: 24px; font-weight: bold; color: #1d2327;"><?php echo wpdd_format_price($total_earnings, $currency); ?></div>
<small style="color: #646970;"><?php printf(__('After %s%% platform fee', 'wp-digital-download'), $commission_rate); ?></small>
</div>
<div class="wpdd-stat-card" style="background: #fff; padding: 20px; border: 1px solid #ccd0d4; border-radius: 4px;">
<h3 style="margin: 0 0 10px; color: #646970;"><?php _e('Available Balance', 'wp-digital-download'); ?></h3>
<div style="font-size: 24px; font-weight: bold; color: #1d2327;"><?php echo wpdd_format_price($current_balance, $currency); ?></div>
<small style="color: #646970;"><?php _e('Ready for payout', 'wp-digital-download'); ?></small>
</div>
</div>
<?php if (!empty($sales)) : ?>
<div class="wpdd-sales-table">
<h2><?php _e('Recent Sales', 'wp-digital-download'); ?></h2>
<table class="wp-list-table widefat fixed striped">
<thead>
<tr>
<th><?php _e('Date', 'wp-digital-download'); ?></th>
<th><?php _e('Product', 'wp-digital-download'); ?></th>
<th><?php _e('Customer', 'wp-digital-download'); ?></th>
<th><?php _e('Sale Amount', 'wp-digital-download'); ?></th>
<th><?php _e('Platform Fee', 'wp-digital-download'); ?></th>
<th><?php _e('Your Earning', 'wp-digital-download'); ?></th>
<th><?php _e('Status', 'wp-digital-download'); ?></th>
</tr>
</thead>
<tbody>
<?php foreach ($sales as $sale) : ?>
<tr>
<td><?php echo esc_html(date_i18n(get_option('date_format'), strtotime($sale->purchase_date))); ?></td>
<td><?php echo esc_html($sale->product_name); ?></td>
<td><?php echo esc_html($sale->customer_name); ?></td>
<td><?php echo wpdd_format_price($sale->total, $currency); ?></td>
<td><?php echo wpdd_format_price($sale->platform_fee, $currency); ?></td>
<td><strong><?php echo wpdd_format_price($sale->creator_earning, $currency); ?></strong></td>
<td>
<span class="wpdd-status-<?php echo esc_attr($sale->status); ?>" style="padding: 2px 8px; border-radius: 3px; font-size: 12px; <?php echo $sale->status === 'completed' ? 'background: #d1e7dd; color: #0f5132;' : 'background: #f8d7da; color: #721c24;'; ?>">
<?php echo esc_html(ucfirst($sale->status)); ?>
</span>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php else : ?>
<div style="background: #fff; padding: 40px; border: 1px solid #ccd0d4; border-radius: 4px; text-align: center;">
<h3><?php _e('No sales yet', 'wp-digital-download'); ?></h3>
<p><?php _e('Once customers purchase your products, your sales data will appear here.', 'wp-digital-download'); ?></p>
</div>
<?php endif; ?>
</div>
<?php
}
public static function render_creator_payouts_page() {
global $wpdb;
if (isset($_POST['request_payout']) && wp_verify_nonce($_POST['wpdd_nonce'], 'wpdd_request_payout')) {
self::handle_payout_request();
}
$user_id = get_current_user_id();
$currency = get_option('wpdd_currency', 'USD');
$current_balance = WPDD_Creator::get_creator_balance($user_id);
$paypal_email = get_user_meta($user_id, 'wpdd_paypal_email', true);
$threshold = floatval(get_option('wpdd_payout_threshold', 0));
// Get payout history
$payouts = $wpdb->get_results($wpdb->prepare(
"SELECT * FROM {$wpdb->prefix}wpdd_payouts
WHERE creator_id = %d
ORDER BY created_at DESC
LIMIT 50",
$user_id
));
?>
<div class="wrap">
<h1><?php _e('My Payouts', 'wp-digital-download'); ?></h1>
<?php if (isset($_GET['message']) && $_GET['message'] === 'payout_requested') : ?>
<div class="notice notice-success is-dismissible">
<p><?php _e('Payout request submitted successfully!', 'wp-digital-download'); ?></p>
</div>
<?php endif; ?>
<div class="wpdd-payout-request" style="background: #fff; padding: 20px; border: 1px solid #ccd0d4; border-radius: 4px; margin-bottom: 30px;">
<h2><?php _e('Request Payout', 'wp-digital-download'); ?></h2>
<div style="display: grid; grid-template-columns: 1fr 2fr; gap: 20px; align-items: start;">
<div>
<h3><?php _e('Current Balance', 'wp-digital-download'); ?></h3>
<div style="font-size: 32px; font-weight: bold; color: #1d2327; margin: 10px 0;">
<?php echo wpdd_format_price($current_balance, $currency); ?>
</div>
<?php if ($threshold > 0) : ?>
<p style="color: #646970; margin: 0;">
<?php printf(__('Minimum for automatic payout: %s', 'wp-digital-download'), wpdd_format_price($threshold, $currency)); ?>
</p>
<?php endif; ?>
</div>
<div>
<?php if (empty($paypal_email)) : ?>
<div class="notice notice-warning" style="margin: 0;">
<p><?php _e('Please add your PayPal email in your profile before requesting a payout.', 'wp-digital-download'); ?></p>
<p><a href="<?php echo esc_url(get_edit_profile_url($user_id)); ?>" class="button"><?php _e('Edit Profile', 'wp-digital-download'); ?></a></p>
</div>
<?php elseif ($current_balance <= 0) : ?>
<div class="notice notice-info" style="margin: 0;">
<p><?php _e('No balance available for payout.', 'wp-digital-download'); ?></p>
</div>
<?php else : ?>
<form method="post">
<?php wp_nonce_field('wpdd_request_payout', 'wpdd_nonce'); ?>
<p><?php _e('PayPal Email:', 'wp-digital-download'); ?> <strong><?php echo esc_html($paypal_email); ?></strong></p>
<p><?php _e('Requesting a payout will notify administrators to process your payment.', 'wp-digital-download'); ?></p>
<button type="submit" name="request_payout" class="button button-primary">
<?php printf(__('Request Payout of %s', 'wp-digital-download'), wpdd_format_price($current_balance, $currency)); ?>
</button>
</form>
<?php endif; ?>
</div>
</div>
</div>
<?php if (!empty($payouts)) : ?>
<div class="wpdd-payout-history">
<h2><?php _e('Payout History', 'wp-digital-download'); ?></h2>
<table class="wp-list-table widefat fixed striped">
<thead>
<tr>
<th><?php _e('Date Requested', 'wp-digital-download'); ?></th>
<th><?php _e('Amount', 'wp-digital-download'); ?></th>
<th><?php _e('PayPal Email', 'wp-digital-download'); ?></th>
<th><?php _e('Status', 'wp-digital-download'); ?></th>
<th><?php _e('Transaction ID', 'wp-digital-download'); ?></th>
<th><?php _e('Processed Date', 'wp-digital-download'); ?></th>
</tr>
</thead>
<tbody>
<?php foreach ($payouts as $payout) : ?>
<tr>
<td><?php echo esc_html(date_i18n(get_option('date_format'), strtotime($payout->created_at))); ?></td>
<td><strong><?php echo wpdd_format_price($payout->amount, $payout->currency); ?></strong></td>
<td><?php echo esc_html($payout->paypal_email); ?></td>
<td>
<?php
$status_colors = array(
'pending' => '#fef3c7; color: #92400e;',
'completed' => '#d1fae5; color: #065f46;',
'failed' => '#fee2e2; color: #991b1b;',
'requested' => '#dbeafe; color: #1e40af;'
);
$status_color = isset($status_colors[$payout->status]) ? $status_colors[$payout->status] : '#f3f4f6; color: #374151;';
?>
<span style="padding: 2px 8px; border-radius: 3px; font-size: 12px; background: <?php echo $status_color; ?>">
<?php echo esc_html(ucfirst($payout->status)); ?>
</span>
</td>
<td><?php echo esc_html($payout->transaction_id ?: '-'); ?></td>
<td>
<?php
echo $payout->processed_at
? esc_html(date_i18n(get_option('date_format'), strtotime($payout->processed_at)))
: '-';
?>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php else : ?>
<div style="background: #fff; padding: 40px; border: 1px solid #ccd0d4; border-radius: 4px; text-align: center;">
<h3><?php _e('No payout history', 'wp-digital-download'); ?></h3>
<p><?php _e('Your payout requests will appear here once you make them.', 'wp-digital-download'); ?></p>
</div>
<?php endif; ?>
</div>
<?php
}
private static function handle_payout_request() {
global $wpdb;
$user_id = get_current_user_id();
$balance = WPDD_Creator::get_creator_balance($user_id);
$paypal_email = get_user_meta($user_id, 'wpdd_paypal_email', true);
if ($balance <= 0 || empty($paypal_email)) {
return;
}
$currency = get_option('wpdd_currency', 'USD');
// Create payout request
$wpdb->insert(
$wpdb->prefix . 'wpdd_payouts',
array(
'creator_id' => $user_id,
'amount' => $balance,
'currency' => $currency,
'paypal_email' => $paypal_email,
'status' => 'requested',
'payout_method' => 'request',
'created_at' => current_time('mysql')
),
array('%d', '%f', '%s', '%s', '%s', '%s', '%s')
);
// Reset balance to 0 since it's now requested
update_user_meta($user_id, 'wpdd_creator_balance', 0);
// Redirect to avoid resubmission
wp_redirect(admin_url('edit.php?post_type=wpdd_product&page=wpdd-creator-payouts&message=payout_requested'));
exit;
}
}