First Commit
This commit is contained in:
435
admin/class-wpdd-admin-payouts.php
Normal file
435
admin/class-wpdd-admin-payouts.php
Normal file
@@ -0,0 +1,435 @@
|
||||
<?php
|
||||
|
||||
if (!defined('ABSPATH')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
class WPDD_Admin_Payouts {
|
||||
|
||||
public static function init() {
|
||||
add_action('admin_menu', array(__CLASS__, 'add_menu_page'));
|
||||
add_action('admin_post_wpdd_process_payout', array(__CLASS__, 'process_payout'));
|
||||
add_action('admin_post_wpdd_bulk_payouts', array(__CLASS__, 'process_bulk_payouts'));
|
||||
add_action('admin_enqueue_scripts', array(__CLASS__, 'enqueue_scripts'));
|
||||
}
|
||||
|
||||
public static function add_menu_page() {
|
||||
add_submenu_page(
|
||||
'edit.php?post_type=wpdd_product',
|
||||
__('Creator Payouts', 'wp-digital-download'),
|
||||
__('Payouts', 'wp-digital-download'),
|
||||
'manage_options',
|
||||
'wpdd-payouts',
|
||||
array(__CLASS__, 'render_page')
|
||||
);
|
||||
}
|
||||
|
||||
public static function enqueue_scripts($hook) {
|
||||
if ($hook !== 'wpdd_product_page_wpdd-payouts') {
|
||||
return;
|
||||
}
|
||||
|
||||
wp_enqueue_script('wpdd-admin-payouts', WPDD_PLUGIN_URL . 'assets/js/admin-payouts.js', array('jquery'), WPDD_VERSION, true);
|
||||
wp_localize_script('wpdd-admin-payouts', 'wpdd_payouts', array(
|
||||
'ajax_url' => 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 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);
|
||||
|
||||
?>
|
||||
<div class="wrap">
|
||||
<h1><?php _e('Creator Payouts', 'wp-digital-download'); ?></h1>
|
||||
|
||||
<?php if (isset($_GET['message'])) : ?>
|
||||
<?php if ($_GET['message'] === 'success') : ?>
|
||||
<div class="notice notice-success is-dismissible">
|
||||
<p><?php _e('Payout processed successfully.', 'wp-digital-download'); ?></p>
|
||||
</div>
|
||||
<?php elseif ($_GET['message'] === 'error') : ?>
|
||||
<div class="notice notice-error is-dismissible">
|
||||
<p><?php _e('Error processing payout. Please try again.', 'wp-digital-download'); ?></p>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="wpdd-payout-stats">
|
||||
<h2><?php _e('Pending Payouts', 'wp-digital-download'); ?></h2>
|
||||
|
||||
<?php if (!empty($creators)) : ?>
|
||||
<form method="post" action="<?php echo admin_url('admin-post.php'); ?>">
|
||||
<input type="hidden" name="action" value="wpdd_bulk_payouts">
|
||||
<?php wp_nonce_field('wpdd_bulk_payouts', 'wpdd_nonce'); ?>
|
||||
|
||||
<table class="wp-list-table widefat fixed striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="check-column">
|
||||
<input type="checkbox" id="select-all-creators">
|
||||
</th>
|
||||
<th><?php _e('Creator', 'wp-digital-download'); ?></th>
|
||||
<th><?php _e('PayPal Email', 'wp-digital-download'); ?></th>
|
||||
<th><?php _e('Current Balance', 'wp-digital-download'); ?></th>
|
||||
<th><?php _e('Total Sales', 'wp-digital-download'); ?></th>
|
||||
<th><?php _e('Net Earnings', 'wp-digital-download'); ?></th>
|
||||
<th><?php _e('Actions', 'wp-digital-download'); ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($creators as $creator) :
|
||||
$total_earnings = WPDD_Creator::get_creator_total_earnings($creator->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;
|
||||
?>
|
||||
<tr <?php echo $auto_eligible ? 'style="background-color: #d4edda;"' : ''; ?>>
|
||||
<td>
|
||||
<?php if ($can_payout) : ?>
|
||||
<input type="checkbox" name="creator_ids[]" value="<?php echo esc_attr($creator->ID); ?>">
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td>
|
||||
<strong><?php echo esc_html($creator->display_name); ?></strong><br>
|
||||
<small><?php echo esc_html($creator->user_email); ?></small>
|
||||
</td>
|
||||
<td>
|
||||
<?php if (!empty($creator->paypal_email)) : ?>
|
||||
<?php echo esc_html($creator->paypal_email); ?>
|
||||
<?php else : ?>
|
||||
<span style="color: #dc3545;"><?php _e('Not set', 'wp-digital-download'); ?></span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td>
|
||||
<strong><?php echo wpdd_format_price($creator->balance, $currency); ?></strong>
|
||||
<?php if ($auto_eligible) : ?>
|
||||
<br><span class="dashicons dashicons-yes" style="color: #28a745;"></span>
|
||||
<small><?php _e('Auto-payout eligible', 'wp-digital-download'); ?></small>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td><?php echo wpdd_format_price($total_earnings, $currency); ?></td>
|
||||
<td><?php echo wpdd_format_price($net_earnings, $currency); ?></td>
|
||||
<td>
|
||||
<?php if ($can_payout) : ?>
|
||||
<form method="post" action="<?php echo admin_url('admin-post.php'); ?>" style="display: inline;">
|
||||
<input type="hidden" name="action" value="wpdd_process_payout">
|
||||
<input type="hidden" name="creator_id" value="<?php echo esc_attr($creator->ID); ?>">
|
||||
<?php wp_nonce_field('wpdd_process_payout_' . $creator->ID, 'wpdd_nonce'); ?>
|
||||
<button type="submit" class="button button-primary wpdd-payout-btn">
|
||||
<?php _e('Process Payout', 'wp-digital-download'); ?>
|
||||
</button>
|
||||
</form>
|
||||
<?php else : ?>
|
||||
<button class="button" disabled><?php _e('Cannot Process', 'wp-digital-download'); ?></button>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div class="tablenav bottom">
|
||||
<div class="alignleft actions">
|
||||
<button type="submit" class="button button-primary" name="bulk_action" value="process">
|
||||
<?php _e('Process Selected Payouts', 'wp-digital-download'); ?>
|
||||
</button>
|
||||
<?php if ($threshold > 0) : ?>
|
||||
<button type="submit" class="button" name="bulk_action" value="auto">
|
||||
<?php printf(__('Process All Above %s', 'wp-digital-download'), wpdd_format_price($threshold, $currency)); ?>
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<?php else : ?>
|
||||
<p><?php _e('No creators with pending payouts.', 'wp-digital-download'); ?></p>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<div class="wpdd-payout-history">
|
||||
<h2><?php _e('Payout History', 'wp-digital-download'); ?></h2>
|
||||
|
||||
<div class="tablenav top">
|
||||
<div class="alignleft actions">
|
||||
<select name="status_filter" onchange="window.location.href='<?php echo admin_url('edit.php?post_type=wpdd_product&page=wpdd-payouts'); ?>&status=' + this.value">
|
||||
<option value="all" <?php selected($status_filter, 'all'); ?>><?php _e('All Statuses', 'wp-digital-download'); ?></option>
|
||||
<option value="pending" <?php selected($status_filter, 'pending'); ?>><?php _e('Pending', 'wp-digital-download'); ?></option>
|
||||
<option value="completed" <?php selected($status_filter, 'completed'); ?>><?php _e('Completed', 'wp-digital-download'); ?></option>
|
||||
<option value="failed" <?php selected($status_filter, 'failed'); ?>><?php _e('Failed', 'wp-digital-download'); ?></option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php if (!empty($payouts)) : ?>
|
||||
<table class="wp-list-table widefat fixed striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><?php _e('Date', 'wp-digital-download'); ?></th>
|
||||
<th><?php _e('Creator', 'wp-digital-download'); ?></th>
|
||||
<th><?php _e('Amount', 'wp-digital-download'); ?></th>
|
||||
<th><?php _e('PayPal Email', 'wp-digital-download'); ?></th>
|
||||
<th><?php _e('Transaction ID', 'wp-digital-download'); ?></th>
|
||||
<th><?php _e('Status', 'wp-digital-download'); ?></th>
|
||||
<th><?php _e('Method', 'wp-digital-download'); ?></th>
|
||||
<th><?php _e('Processed By', 'wp-digital-download'); ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($payouts as $payout) :
|
||||
$processor = $payout->processed_by ? get_userdata($payout->processed_by) : null;
|
||||
?>
|
||||
<tr>
|
||||
<td>
|
||||
<?php echo esc_html(date_i18n(get_option('date_format') . ' ' . get_option('time_format'), strtotime($payout->created_at))); ?>
|
||||
<?php if ($payout->processed_at) : ?>
|
||||
<br><small><?php _e('Processed:', 'wp-digital-download'); ?> <?php echo esc_html(date_i18n(get_option('date_format'), strtotime($payout->processed_at))); ?></small>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td>
|
||||
<strong><?php echo esc_html($payout->display_name); ?></strong><br>
|
||||
<small><?php echo esc_html($payout->user_email); ?></small>
|
||||
</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 echo esc_html($payout->transaction_id ?: '-'); ?>
|
||||
<?php if ($payout->notes) : ?>
|
||||
<br><small><?php echo esc_html($payout->notes); ?></small>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td>
|
||||
<?php
|
||||
$status_class = '';
|
||||
switch($payout->status) {
|
||||
case 'completed':
|
||||
$status_class = 'notice-success';
|
||||
break;
|
||||
case 'failed':
|
||||
$status_class = 'notice-error';
|
||||
break;
|
||||
case 'pending':
|
||||
$status_class = 'notice-warning';
|
||||
break;
|
||||
}
|
||||
?>
|
||||
<span class="notice <?php echo esc_attr($status_class); ?>" style="padding: 2px 8px; display: inline-block;">
|
||||
<?php echo esc_html(ucfirst($payout->status)); ?>
|
||||
</span>
|
||||
</td>
|
||||
<td><?php echo esc_html(ucfirst($payout->payout_method)); ?></td>
|
||||
<td>
|
||||
<?php if ($processor) : ?>
|
||||
<?php echo esc_html($processor->display_name); ?>
|
||||
<?php else : ?>
|
||||
<?php echo $payout->payout_method === 'automatic' ? __('System', 'wp-digital-download') : '-'; ?>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php else : ?>
|
||||
<p><?php _e('No payout history found.', 'wp-digital-download'); ?></p>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.wpdd-payout-stats,
|
||||
.wpdd-payout-history {
|
||||
margin-top: 30px;
|
||||
background: #fff;
|
||||
padding: 20px;
|
||||
border: 1px solid #ccd0d4;
|
||||
box-shadow: 0 1px 1px rgba(0,0,0,.04);
|
||||
}
|
||||
.wpdd-payout-btn:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
#select-all-creators {
|
||||
margin: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
jQuery(document).ready(function($) {
|
||||
$('#select-all-creators').on('change', function() {
|
||||
$('input[name="creator_ids[]"]').prop('checked', this.checked);
|
||||
});
|
||||
|
||||
$('.wpdd-payout-btn').on('click', function(e) {
|
||||
if (!confirm(wpdd_payouts.confirm_payout)) {
|
||||
e.preventDefault();
|
||||
}
|
||||
});
|
||||
|
||||
$('button[name="bulk_action"]').on('click', function(e) {
|
||||
var checkedCount = $('input[name="creator_ids[]"]:checked').length;
|
||||
if (checkedCount === 0) {
|
||||
alert('Please select at least one creator for payout.');
|
||||
e.preventDefault();
|
||||
} else if (!confirm(wpdd_payouts.confirm_bulk)) {
|
||||
e.preventDefault();
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
public static function process_payout() {
|
||||
if (!current_user_can('manage_options')) {
|
||||
wp_die(__('You do not have permission to perform this action.', 'wp-digital-download'));
|
||||
}
|
||||
|
||||
$creator_id = isset($_POST['creator_id']) ? intval($_POST['creator_id']) : 0;
|
||||
|
||||
if (!$creator_id || !wp_verify_nonce($_POST['wpdd_nonce'], 'wpdd_process_payout_' . $creator_id)) {
|
||||
wp_redirect(admin_url('edit.php?post_type=wpdd_product&page=wpdd-payouts&message=error'));
|
||||
exit;
|
||||
}
|
||||
|
||||
$result = self::create_payout($creator_id);
|
||||
|
||||
if ($result) {
|
||||
wp_redirect(admin_url('edit.php?post_type=wpdd_product&page=wpdd-payouts&message=success'));
|
||||
} else {
|
||||
wp_redirect(admin_url('edit.php?post_type=wpdd_product&page=wpdd-payouts&message=error'));
|
||||
}
|
||||
exit;
|
||||
}
|
||||
|
||||
public static function process_bulk_payouts() {
|
||||
if (!current_user_can('manage_options')) {
|
||||
wp_die(__('You do not have permission to perform this action.', 'wp-digital-download'));
|
||||
}
|
||||
|
||||
if (!wp_verify_nonce($_POST['wpdd_nonce'], 'wpdd_bulk_payouts')) {
|
||||
wp_redirect(admin_url('edit.php?post_type=wpdd_product&page=wpdd-payouts&message=error'));
|
||||
exit;
|
||||
}
|
||||
|
||||
$bulk_action = isset($_POST['bulk_action']) ? sanitize_text_field($_POST['bulk_action']) : '';
|
||||
|
||||
if ($bulk_action === 'auto') {
|
||||
// Process all creators above threshold
|
||||
$threshold = floatval(get_option('wpdd_payout_threshold', 0));
|
||||
if ($threshold > 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;
|
||||
|
||||
$balance = WPDD_Creator::get_creator_balance($creator_id);
|
||||
$paypal_email = get_user_meta($creator_id, 'wpdd_paypal_email', true);
|
||||
|
||||
if ($balance <= 0 || empty($paypal_email)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$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;
|
||||
|
||||
// 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')
|
||||
);
|
||||
|
||||
// Reset creator balance
|
||||
update_user_meta($creator_id, 'wpdd_creator_balance', 0);
|
||||
|
||||
return true;
|
||||
} 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 false;
|
||||
}
|
||||
}
|
||||
}
|
920
admin/class-wpdd-admin.php
Normal file
920
admin/class-wpdd-admin.php
Normal file
@@ -0,0 +1,920 @@
|
||||
<?php
|
||||
|
||||
if (!defined('ABSPATH')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
class WPDD_Admin {
|
||||
|
||||
public static function init() {
|
||||
add_action('admin_menu', array(__CLASS__, 'add_admin_menus'));
|
||||
add_filter('manage_wpdd_product_posts_columns', array(__CLASS__, 'add_product_columns'));
|
||||
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('admin_init', array(__CLASS__, 'handle_admin_actions'));
|
||||
|
||||
// Initialize admin payouts
|
||||
if (class_exists('WPDD_Admin_Payouts')) {
|
||||
WPDD_Admin_Payouts::init();
|
||||
}
|
||||
}
|
||||
|
||||
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')
|
||||
);
|
||||
|
||||
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')
|
||||
);
|
||||
}
|
||||
|
||||
public static function add_product_columns($columns) {
|
||||
$new_columns = array();
|
||||
|
||||
foreach ($columns as $key => $value) {
|
||||
$new_columns[$key] = $value;
|
||||
|
||||
if ($key === 'title') {
|
||||
$new_columns['wpdd_price'] = __('Price', 'wp-digital-download');
|
||||
$new_columns['wpdd_sales'] = __('Sales', 'wp-digital-download');
|
||||
$new_columns['wpdd_revenue'] = __('Revenue', 'wp-digital-download');
|
||||
$new_columns['wpdd_files'] = __('Files', 'wp-digital-download');
|
||||
}
|
||||
}
|
||||
|
||||
return $new_columns;
|
||||
}
|
||||
|
||||
public static function render_product_columns($column, $post_id) {
|
||||
switch ($column) {
|
||||
case 'wpdd_price':
|
||||
$price = get_post_meta($post_id, '_wpdd_price', true);
|
||||
$sale_price = get_post_meta($post_id, '_wpdd_sale_price', true);
|
||||
$is_free = get_post_meta($post_id, '_wpdd_is_free', true);
|
||||
|
||||
if ($is_free) {
|
||||
echo '<span style="color: green;">' . __('Free', 'wp-digital-download') . '</span>';
|
||||
} elseif ($sale_price && $sale_price < $price) {
|
||||
echo '<del>$' . number_format($price, 2) . '</del> ';
|
||||
echo '<strong>$' . number_format($sale_price, 2) . '</strong>';
|
||||
} else {
|
||||
echo '$' . number_format($price, 2);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'wpdd_sales':
|
||||
global $wpdb;
|
||||
$sales = $wpdb->get_var($wpdb->prepare(
|
||||
"SELECT COUNT(*) FROM {$wpdb->prefix}wpdd_orders
|
||||
WHERE product_id = %d AND status = 'completed'",
|
||||
$post_id
|
||||
));
|
||||
echo intval($sales);
|
||||
break;
|
||||
|
||||
case 'wpdd_revenue':
|
||||
global $wpdb;
|
||||
$revenue = $wpdb->get_var($wpdb->prepare(
|
||||
"SELECT SUM(amount) FROM {$wpdb->prefix}wpdd_orders
|
||||
WHERE product_id = %d AND status = 'completed'",
|
||||
$post_id
|
||||
));
|
||||
echo '$' . number_format($revenue ?: 0, 2);
|
||||
break;
|
||||
|
||||
case 'wpdd_files':
|
||||
$files = get_post_meta($post_id, '_wpdd_files', true);
|
||||
$count = is_array($files) ? count($files) : 0;
|
||||
echo $count;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public static function make_columns_sortable($columns) {
|
||||
$columns['wpdd_price'] = 'wpdd_price';
|
||||
$columns['wpdd_sales'] = 'wpdd_sales';
|
||||
$columns['wpdd_revenue'] = 'wpdd_revenue';
|
||||
return $columns;
|
||||
}
|
||||
|
||||
public static function sort_products_by_column($query) {
|
||||
if (!is_admin() || !$query->is_main_query()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($query->get('post_type') !== 'wpdd_product') {
|
||||
return;
|
||||
}
|
||||
|
||||
$orderby = $query->get('orderby');
|
||||
|
||||
switch ($orderby) {
|
||||
case 'wpdd_price':
|
||||
$query->set('meta_key', '_wpdd_price');
|
||||
$query->set('orderby', 'meta_value_num');
|
||||
break;
|
||||
|
||||
case 'wpdd_sales':
|
||||
$query->set('meta_key', '_wpdd_sales_count');
|
||||
$query->set('orderby', 'meta_value_num');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public static function render_orders_page() {
|
||||
global $wpdb;
|
||||
|
||||
$page = isset($_GET['paged']) ? max(1, intval($_GET['paged'])) : 1;
|
||||
$per_page = 20;
|
||||
$offset = ($page - 1) * $per_page;
|
||||
|
||||
$where = array('1=1');
|
||||
|
||||
if (isset($_GET['status']) && $_GET['status']) {
|
||||
$where[] = $wpdb->prepare("o.status = %s", sanitize_text_field($_GET['status']));
|
||||
}
|
||||
|
||||
if (isset($_GET['product_id']) && $_GET['product_id']) {
|
||||
$where[] = $wpdb->prepare("o.product_id = %d", intval($_GET['product_id']));
|
||||
}
|
||||
|
||||
if (isset($_GET['search']) && $_GET['search']) {
|
||||
$search = '%' . $wpdb->esc_like($_GET['search']) . '%';
|
||||
$where[] = $wpdb->prepare(
|
||||
"(o.order_number LIKE %s OR o.customer_email LIKE %s OR o.customer_name LIKE %s)",
|
||||
$search, $search, $search
|
||||
);
|
||||
}
|
||||
|
||||
$where_clause = implode(' AND ', $where);
|
||||
|
||||
$total = $wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->prefix}wpdd_orders o WHERE {$where_clause}");
|
||||
|
||||
$orders = $wpdb->get_results($wpdb->prepare(
|
||||
"SELECT o.*, p.post_title as product_name
|
||||
FROM {$wpdb->prefix}wpdd_orders o
|
||||
LEFT JOIN {$wpdb->posts} p ON o.product_id = p.ID
|
||||
WHERE {$where_clause}
|
||||
ORDER BY o.purchase_date DESC
|
||||
LIMIT %d OFFSET %d",
|
||||
$per_page,
|
||||
$offset
|
||||
));
|
||||
?>
|
||||
<div class="wrap">
|
||||
<h1><?php _e('Orders', 'wp-digital-download'); ?></h1>
|
||||
|
||||
<form method="get">
|
||||
<input type="hidden" name="post_type" value="wpdd_product" />
|
||||
<input type="hidden" name="page" value="wpdd-orders" />
|
||||
|
||||
<div class="tablenav top">
|
||||
<div class="alignleft actions">
|
||||
<select name="status">
|
||||
<option value=""><?php _e('All Statuses', 'wp-digital-download'); ?></option>
|
||||
<option value="pending" <?php selected(isset($_GET['status']) && $_GET['status'] == 'pending'); ?>>
|
||||
<?php _e('Pending', 'wp-digital-download'); ?>
|
||||
</option>
|
||||
<option value="completed" <?php selected(isset($_GET['status']) && $_GET['status'] == 'completed'); ?>>
|
||||
<?php _e('Completed', 'wp-digital-download'); ?>
|
||||
</option>
|
||||
<option value="failed" <?php selected(isset($_GET['status']) && $_GET['status'] == 'failed'); ?>>
|
||||
<?php _e('Failed', 'wp-digital-download'); ?>
|
||||
</option>
|
||||
</select>
|
||||
|
||||
<input type="text" name="search" placeholder="<?php _e('Search orders...', 'wp-digital-download'); ?>"
|
||||
value="<?php echo isset($_GET['search']) ? esc_attr($_GET['search']) : ''; ?>" />
|
||||
|
||||
<input type="submit" class="button" value="<?php _e('Filter', 'wp-digital-download'); ?>" />
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<table class="wp-list-table widefat fixed striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><?php _e('Order', 'wp-digital-download'); ?></th>
|
||||
<th><?php _e('Product', 'wp-digital-download'); ?></th>
|
||||
<th><?php _e('Customer', 'wp-digital-download'); ?></th>
|
||||
<th><?php _e('Amount', 'wp-digital-download'); ?></th>
|
||||
<th><?php _e('Status', 'wp-digital-download'); ?></th>
|
||||
<th><?php _e('Date', 'wp-digital-download'); ?></th>
|
||||
<th><?php _e('Actions', 'wp-digital-download'); ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php if ($orders) : ?>
|
||||
<?php foreach ($orders as $order) : ?>
|
||||
<tr>
|
||||
<td><strong>#<?php echo esc_html($order->order_number); ?></strong></td>
|
||||
<td>
|
||||
<a href="<?php echo get_edit_post_link($order->product_id); ?>">
|
||||
<?php echo esc_html($order->product_name); ?>
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
<?php echo esc_html($order->customer_name); ?><br>
|
||||
<small><?php echo esc_html($order->customer_email); ?></small>
|
||||
</td>
|
||||
<td>$<?php echo number_format($order->amount, 2); ?></td>
|
||||
<td>
|
||||
<span class="wpdd-status wpdd-status-<?php echo esc_attr($order->status); ?>">
|
||||
<?php echo ucfirst($order->status); ?>
|
||||
</span>
|
||||
</td>
|
||||
<td><?php echo date_i18n(get_option('date_format'), strtotime($order->purchase_date)); ?></td>
|
||||
<td>
|
||||
<a href="<?php echo wp_nonce_url(
|
||||
add_query_arg(array(
|
||||
'action' => 'wpdd_view_order',
|
||||
'order_id' => $order->id
|
||||
)),
|
||||
'wpdd_view_order_' . $order->id
|
||||
); ?>" class="button button-small">
|
||||
<?php _e('View', 'wp-digital-download'); ?>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php else : ?>
|
||||
<tr>
|
||||
<td colspan="7"><?php _e('No orders found.', 'wp-digital-download'); ?></td>
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<?php
|
||||
$total_pages = ceil($total / $per_page);
|
||||
if ($total_pages > 1) {
|
||||
echo '<div class="tablenav bottom"><div class="tablenav-pages">';
|
||||
echo paginate_links(array(
|
||||
'base' => add_query_arg('paged', '%#%'),
|
||||
'format' => '',
|
||||
'current' => $page,
|
||||
'total' => $total_pages
|
||||
));
|
||||
echo '</div></div>';
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.wpdd-status {
|
||||
padding: 3px 8px;
|
||||
border-radius: 3px;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
}
|
||||
.wpdd-status-completed { background: #d4edda; color: #155724; }
|
||||
.wpdd-status-pending { background: #fff3cd; color: #856404; }
|
||||
.wpdd-status-failed { background: #f8d7da; color: #721c24; }
|
||||
</style>
|
||||
<?php
|
||||
}
|
||||
|
||||
public static function render_reports_page() {
|
||||
global $wpdb;
|
||||
|
||||
$date_range = isset($_GET['range']) ? sanitize_text_field($_GET['range']) : '30days';
|
||||
|
||||
switch ($date_range) {
|
||||
case '7days':
|
||||
$start_date = date('Y-m-d', strtotime('-7 days'));
|
||||
break;
|
||||
case '30days':
|
||||
$start_date = date('Y-m-d', strtotime('-30 days'));
|
||||
break;
|
||||
case '3months':
|
||||
$start_date = date('Y-m-d', strtotime('-3 months'));
|
||||
break;
|
||||
case 'year':
|
||||
$start_date = date('Y-m-d', strtotime('-1 year'));
|
||||
break;
|
||||
default:
|
||||
$start_date = date('Y-m-d', strtotime('-30 days'));
|
||||
}
|
||||
|
||||
$stats = $wpdb->get_row($wpdb->prepare(
|
||||
"SELECT
|
||||
COUNT(*) as total_orders,
|
||||
SUM(amount) as total_revenue,
|
||||
COUNT(DISTINCT customer_id) as unique_customers,
|
||||
COUNT(DISTINCT product_id) as products_sold
|
||||
FROM {$wpdb->prefix}wpdd_orders
|
||||
WHERE status = 'completed'
|
||||
AND purchase_date >= %s",
|
||||
$start_date
|
||||
));
|
||||
|
||||
$top_products = $wpdb->get_results($wpdb->prepare(
|
||||
"SELECT
|
||||
p.ID,
|
||||
p.post_title,
|
||||
COUNT(o.id) as sales,
|
||||
SUM(o.amount) as revenue
|
||||
FROM {$wpdb->prefix}wpdd_orders o
|
||||
INNER JOIN {$wpdb->posts} p ON o.product_id = p.ID
|
||||
WHERE o.status = 'completed'
|
||||
AND o.purchase_date >= %s
|
||||
GROUP BY p.ID
|
||||
ORDER BY revenue DESC
|
||||
LIMIT 10",
|
||||
$start_date
|
||||
));
|
||||
|
||||
$top_creators = $wpdb->get_results($wpdb->prepare(
|
||||
"SELECT
|
||||
u.ID,
|
||||
u.display_name,
|
||||
COUNT(o.id) as sales,
|
||||
SUM(o.amount) as revenue
|
||||
FROM {$wpdb->prefix}wpdd_orders o
|
||||
INNER JOIN {$wpdb->users} u ON o.creator_id = u.ID
|
||||
WHERE o.status = 'completed'
|
||||
AND o.purchase_date >= %s
|
||||
GROUP BY u.ID
|
||||
ORDER BY revenue DESC
|
||||
LIMIT 10",
|
||||
$start_date
|
||||
));
|
||||
?>
|
||||
<div class="wrap">
|
||||
<h1><?php _e('Reports', 'wp-digital-download'); ?></h1>
|
||||
|
||||
<div class="wpdd-date-filter">
|
||||
<form method="get">
|
||||
<input type="hidden" name="post_type" value="wpdd_product" />
|
||||
<input type="hidden" name="page" value="wpdd-reports" />
|
||||
|
||||
<select name="range" onchange="this.form.submit()">
|
||||
<option value="7days" <?php selected($date_range, '7days'); ?>>
|
||||
<?php _e('Last 7 Days', 'wp-digital-download'); ?>
|
||||
</option>
|
||||
<option value="30days" <?php selected($date_range, '30days'); ?>>
|
||||
<?php _e('Last 30 Days', 'wp-digital-download'); ?>
|
||||
</option>
|
||||
<option value="3months" <?php selected($date_range, '3months'); ?>>
|
||||
<?php _e('Last 3 Months', 'wp-digital-download'); ?>
|
||||
</option>
|
||||
<option value="year" <?php selected($date_range, 'year'); ?>>
|
||||
<?php _e('Last Year', 'wp-digital-download'); ?>
|
||||
</option>
|
||||
</select>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="wpdd-stats-grid">
|
||||
<div class="wpdd-stat-box">
|
||||
<h3><?php _e('Total Revenue', 'wp-digital-download'); ?></h3>
|
||||
<p class="wpdd-stat-value">$<?php echo number_format($stats->total_revenue ?: 0, 2); ?></p>
|
||||
</div>
|
||||
|
||||
<div class="wpdd-stat-box">
|
||||
<h3><?php _e('Total Orders', 'wp-digital-download'); ?></h3>
|
||||
<p class="wpdd-stat-value"><?php echo intval($stats->total_orders); ?></p>
|
||||
</div>
|
||||
|
||||
<div class="wpdd-stat-box">
|
||||
<h3><?php _e('Unique Customers', 'wp-digital-download'); ?></h3>
|
||||
<p class="wpdd-stat-value"><?php echo intval($stats->unique_customers); ?></p>
|
||||
</div>
|
||||
|
||||
<div class="wpdd-stat-box">
|
||||
<h3><?php _e('Products Sold', 'wp-digital-download'); ?></h3>
|
||||
<p class="wpdd-stat-value"><?php echo intval($stats->products_sold); ?></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="wpdd-reports-tables">
|
||||
<div class="wpdd-report-section">
|
||||
<h2><?php _e('Top Products', 'wp-digital-download'); ?></h2>
|
||||
<table class="wp-list-table widefat fixed striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><?php _e('Product', 'wp-digital-download'); ?></th>
|
||||
<th><?php _e('Sales', 'wp-digital-download'); ?></th>
|
||||
<th><?php _e('Revenue', 'wp-digital-download'); ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php if ($top_products) : ?>
|
||||
<?php foreach ($top_products as $product) : ?>
|
||||
<tr>
|
||||
<td>
|
||||
<a href="<?php echo get_edit_post_link($product->ID); ?>">
|
||||
<?php echo esc_html($product->post_title); ?>
|
||||
</a>
|
||||
</td>
|
||||
<td><?php echo intval($product->sales); ?></td>
|
||||
<td>$<?php echo number_format($product->revenue, 2); ?></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php else : ?>
|
||||
<tr>
|
||||
<td colspan="3"><?php _e('No data available.', 'wp-digital-download'); ?></td>
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="wpdd-report-section">
|
||||
<h2><?php _e('Top Creators', 'wp-digital-download'); ?></h2>
|
||||
<table class="wp-list-table widefat fixed striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><?php _e('Creator', 'wp-digital-download'); ?></th>
|
||||
<th><?php _e('Sales', 'wp-digital-download'); ?></th>
|
||||
<th><?php _e('Revenue', 'wp-digital-download'); ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php if ($top_creators) : ?>
|
||||
<?php foreach ($top_creators as $creator) : ?>
|
||||
<tr>
|
||||
<td>
|
||||
<a href="<?php echo get_edit_user_link($creator->ID); ?>">
|
||||
<?php echo esc_html($creator->display_name); ?>
|
||||
</a>
|
||||
</td>
|
||||
<td><?php echo intval($creator->sales); ?></td>
|
||||
<td>$<?php echo number_format($creator->revenue, 2); ?></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php else : ?>
|
||||
<tr>
|
||||
<td colspan="3"><?php _e('No data available.', 'wp-digital-download'); ?></td>
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.wpdd-date-filter {
|
||||
margin: 20px 0;
|
||||
}
|
||||
.wpdd-stats-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||
gap: 20px;
|
||||
margin: 30px 0;
|
||||
}
|
||||
.wpdd-stat-box {
|
||||
background: white;
|
||||
padding: 20px;
|
||||
border: 1px solid #ccd0d4;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.wpdd-stat-box h3 {
|
||||
margin: 0 0 10px 0;
|
||||
color: #23282d;
|
||||
}
|
||||
.wpdd-stat-value {
|
||||
font-size: 32px;
|
||||
font-weight: 600;
|
||||
color: #2271b1;
|
||||
margin: 0;
|
||||
}
|
||||
.wpdd-reports-tables {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 30px;
|
||||
margin-top: 30px;
|
||||
}
|
||||
.wpdd-report-section h2 {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
@media (max-width: 1200px) {
|
||||
.wpdd-reports-tables {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<?php
|
||||
}
|
||||
|
||||
public static function render_customers_page() {
|
||||
global $wpdb;
|
||||
|
||||
// Get all users who have made purchases, regardless of their role
|
||||
$customers = $wpdb->get_results(
|
||||
"SELECT
|
||||
u.ID,
|
||||
u.user_email,
|
||||
u.display_name,
|
||||
u.user_registered,
|
||||
COUNT(o.id) as total_orders,
|
||||
SUM(o.amount) as total_spent,
|
||||
MAX(o.purchase_date) as last_order_date
|
||||
FROM {$wpdb->users} u
|
||||
INNER JOIN {$wpdb->prefix}wpdd_orders o ON u.ID = o.customer_id AND o.status = 'completed'
|
||||
GROUP BY u.ID
|
||||
ORDER BY total_spent DESC"
|
||||
);
|
||||
?>
|
||||
<div class="wrap">
|
||||
<h1><?php _e('Customers', 'wp-digital-download'); ?></h1>
|
||||
|
||||
<table class="wp-list-table widefat fixed striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><?php _e('Customer', 'wp-digital-download'); ?></th>
|
||||
<th><?php _e('Email', 'wp-digital-download'); ?></th>
|
||||
<th><?php _e('Orders', 'wp-digital-download'); ?></th>
|
||||
<th><?php _e('Total Spent', 'wp-digital-download'); ?></th>
|
||||
<th><?php _e('Registered', 'wp-digital-download'); ?></th>
|
||||
<th><?php _e('Last Order', 'wp-digital-download'); ?></th>
|
||||
<th><?php _e('Actions', 'wp-digital-download'); ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php if ($customers) : ?>
|
||||
<?php foreach ($customers as $customer) : ?>
|
||||
<tr>
|
||||
<td>
|
||||
<strong><?php echo esc_html($customer->display_name); ?></strong>
|
||||
</td>
|
||||
<td><?php echo esc_html($customer->user_email); ?></td>
|
||||
<td><?php echo intval($customer->total_orders); ?></td>
|
||||
<td>$<?php echo number_format($customer->total_spent ?: 0, 2); ?></td>
|
||||
<td><?php echo date_i18n(get_option('date_format'), strtotime($customer->user_registered)); ?></td>
|
||||
<td>
|
||||
<?php
|
||||
echo $customer->last_order_date
|
||||
? date_i18n(get_option('date_format'), strtotime($customer->last_order_date))
|
||||
: '-';
|
||||
?>
|
||||
</td>
|
||||
<td>
|
||||
<a href="<?php echo get_edit_user_link($customer->ID); ?>" class="button button-small">
|
||||
<?php _e('Edit', 'wp-digital-download'); ?>
|
||||
</a>
|
||||
<a href="<?php echo add_query_arg(array(
|
||||
'post_type' => 'wpdd_product',
|
||||
'page' => 'wpdd-orders',
|
||||
'customer_id' => $customer->ID
|
||||
), admin_url('edit.php')); ?>" class="button button-small">
|
||||
<?php _e('View Orders', 'wp-digital-download'); ?>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php else : ?>
|
||||
<tr>
|
||||
<td colspan="7"><?php _e('No customers found.', 'wp-digital-download'); ?></td>
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
public static function handle_admin_actions() {
|
||||
if (isset($_GET['action']) && $_GET['action'] === 'wpdd_view_order') {
|
||||
if (!isset($_GET['order_id']) || !wp_verify_nonce($_GET['_wpnonce'] ?? '', 'wpdd_view_order_' . $_GET['order_id'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
self::view_order_details(intval($_GET['order_id']));
|
||||
}
|
||||
}
|
||||
|
||||
private static function view_order_details($order_id) {
|
||||
global $wpdb;
|
||||
|
||||
$order = $wpdb->get_row($wpdb->prepare(
|
||||
"SELECT o.*, p.post_title as product_name
|
||||
FROM {$wpdb->prefix}wpdd_orders o
|
||||
LEFT JOIN {$wpdb->posts} p ON o.product_id = p.ID
|
||||
WHERE o.id = %d",
|
||||
$order_id
|
||||
));
|
||||
|
||||
if (!$order) {
|
||||
wp_die(__('Order not found.', 'wp-digital-download'));
|
||||
}
|
||||
|
||||
include WPDD_PLUGIN_PATH . 'admin/views/order-details.php';
|
||||
exit;
|
||||
}
|
||||
|
||||
public static function render_shortcodes_page() {
|
||||
?>
|
||||
<div class="wrap">
|
||||
<h1><?php _e('Available Shortcodes', 'wp-digital-download'); ?></h1>
|
||||
|
||||
<div class="wpdd-shortcodes-intro">
|
||||
<p><?php _e('Use these shortcodes to display digital download content on your pages and posts. Simply copy and paste the shortcode into any page or post editor.', 'wp-digital-download'); ?></p>
|
||||
</div>
|
||||
|
||||
<div class="wpdd-shortcodes-grid">
|
||||
|
||||
<!-- Shop Shortcode -->
|
||||
<div class="wpdd-shortcode-card">
|
||||
<h3><?php _e('Shop Page', 'wp-digital-download'); ?></h3>
|
||||
<div class="wpdd-shortcode-example">
|
||||
<code>[wpdd_shop]</code>
|
||||
</div>
|
||||
<p><?php _e('Displays a grid of all available products with filtering and pagination.', 'wp-digital-download'); ?></p>
|
||||
|
||||
<h4><?php _e('Available Parameters:', 'wp-digital-download'); ?></h4>
|
||||
<ul class="wpdd-params-list">
|
||||
<li><strong>posts_per_page</strong> - Number of products per page (default: 12)</li>
|
||||
<li><strong>columns</strong> - Grid columns (default: 3, options: 1-6)</li>
|
||||
<li><strong>orderby</strong> - Sort order (date, title, price, menu_order)</li>
|
||||
<li><strong>order</strong> - ASC or DESC (default: DESC)</li>
|
||||
<li><strong>category</strong> - Show only specific categories (comma separated slugs)</li>
|
||||
<li><strong>show_filters</strong> - Show search/filter form (yes/no, default: yes)</li>
|
||||
</ul>
|
||||
|
||||
<h4><?php _e('Examples:', 'wp-digital-download'); ?></h4>
|
||||
<div class="wpdd-shortcode-examples">
|
||||
<code>[wpdd_shop posts_per_page="6" columns="2"]</code><br>
|
||||
<code>[wpdd_shop category="music,videos" show_filters="no"]</code><br>
|
||||
<code>[wpdd_shop orderby="price" order="ASC" columns="4"]</code>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Checkout Shortcode -->
|
||||
<div class="wpdd-shortcode-card">
|
||||
<h3><?php _e('Checkout Page', 'wp-digital-download'); ?></h3>
|
||||
<div class="wpdd-shortcode-example">
|
||||
<code>[wpdd_checkout]</code>
|
||||
</div>
|
||||
<p><?php _e('Displays the checkout form for purchasing products. Typically used on a dedicated checkout page.', 'wp-digital-download'); ?></p>
|
||||
|
||||
<p class="wpdd-note"><?php _e('Note: This shortcode automatically detects the product to purchase from the URL parameter.', 'wp-digital-download'); ?></p>
|
||||
</div>
|
||||
|
||||
<!-- Customer Purchases Shortcode -->
|
||||
<div class="wpdd-shortcode-card">
|
||||
<h3><?php _e('Customer Purchases', 'wp-digital-download'); ?></h3>
|
||||
<div class="wpdd-shortcode-example">
|
||||
<code>[wpdd_customer_purchases]</code>
|
||||
</div>
|
||||
<p><?php _e('Shows a table of customer\'s purchase history with download links. Requires user to be logged in.', 'wp-digital-download'); ?></p>
|
||||
|
||||
<p class="wpdd-note"><?php _e('Note: This page also supports guest access via email links sent after purchase.', 'wp-digital-download'); ?></p>
|
||||
</div>
|
||||
|
||||
<!-- Thank You Shortcode -->
|
||||
<div class="wpdd-shortcode-card">
|
||||
<h3><?php _e('Thank You Page', 'wp-digital-download'); ?></h3>
|
||||
<div class="wpdd-shortcode-example">
|
||||
<code>[wpdd_thank_you]</code>
|
||||
</div>
|
||||
<p><?php _e('Displays order confirmation and download links after successful purchase. Used on the thank you page.', 'wp-digital-download'); ?></p>
|
||||
|
||||
<p class="wpdd-note"><?php _e('Note: This shortcode requires an order_id parameter in the URL.', 'wp-digital-download'); ?></p>
|
||||
</div>
|
||||
|
||||
<!-- Single Product Shortcode -->
|
||||
<div class="wpdd-shortcode-card">
|
||||
<h3><?php _e('Single Product', 'wp-digital-download'); ?></h3>
|
||||
<div class="wpdd-shortcode-example">
|
||||
<code>[wpdd_single_product id="123"]</code>
|
||||
</div>
|
||||
<p><?php _e('Display a single product card anywhere on your site.', 'wp-digital-download'); ?></p>
|
||||
|
||||
<h4><?php _e('Parameters:', 'wp-digital-download'); ?></h4>
|
||||
<ul class="wpdd-params-list">
|
||||
<li><strong>id</strong> - Product ID (required)</li>
|
||||
</ul>
|
||||
|
||||
<h4><?php _e('Example:', 'wp-digital-download'); ?></h4>
|
||||
<div class="wpdd-shortcode-examples">
|
||||
<code>[wpdd_single_product id="456"]</code>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Buy Button Shortcode -->
|
||||
<div class="wpdd-shortcode-card">
|
||||
<h3><?php _e('Buy Button', 'wp-digital-download'); ?></h3>
|
||||
<div class="wpdd-shortcode-example">
|
||||
<code>[wpdd_buy_button id="123"]</code>
|
||||
</div>
|
||||
<p><?php _e('Display just a buy button for a specific product.', 'wp-digital-download'); ?></p>
|
||||
|
||||
<h4><?php _e('Parameters:', 'wp-digital-download'); ?></h4>
|
||||
<ul class="wpdd-params-list">
|
||||
<li><strong>id</strong> - Product ID (default: current post ID)</li>
|
||||
<li><strong>text</strong> - Button text (default: "Buy Now")</li>
|
||||
<li><strong>class</strong> - CSS class for styling</li>
|
||||
</ul>
|
||||
|
||||
<h4><?php _e('Examples:', 'wp-digital-download'); ?></h4>
|
||||
<div class="wpdd-shortcode-examples">
|
||||
<code>[wpdd_buy_button id="789" text="Purchase Now"]</code><br>
|
||||
<code>[wpdd_buy_button text="Get This Product" class="my-custom-button"]</code>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Page Setup Section -->
|
||||
<div class="wpdd-page-setup">
|
||||
<h2><?php _e('Required Pages Setup', 'wp-digital-download'); ?></h2>
|
||||
<p><?php _e('For the plugin to work correctly, you need these pages with their respective shortcodes:', 'wp-digital-download'); ?></p>
|
||||
|
||||
<table class="wp-list-table widefat fixed striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><?php _e('Page Name', 'wp-digital-download'); ?></th>
|
||||
<th><?php _e('Shortcode', 'wp-digital-download'); ?></th>
|
||||
<th><?php _e('Purpose', 'wp-digital-download'); ?></th>
|
||||
<th><?php _e('Status', 'wp-digital-download'); ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><strong><?php _e('Shop', 'wp-digital-download'); ?></strong></td>
|
||||
<td><code>[wpdd_shop]</code></td>
|
||||
<td><?php _e('Main product listing page', 'wp-digital-download'); ?></td>
|
||||
<td>
|
||||
<?php
|
||||
$shop_page_id = get_option('wpdd_shop_page_id');
|
||||
if ($shop_page_id && get_post($shop_page_id)) {
|
||||
echo '<span style="color: green;">✓ ' . __('Created', 'wp-digital-download') . '</span>';
|
||||
echo ' (<a href="' . get_edit_post_link($shop_page_id) . '">' . __('Edit', 'wp-digital-download') . '</a>)';
|
||||
} else {
|
||||
echo '<span style="color: red;">✗ ' . __('Missing', 'wp-digital-download') . '</span>';
|
||||
}
|
||||
?>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong><?php _e('Checkout', 'wp-digital-download'); ?></strong></td>
|
||||
<td><code>[wpdd_checkout]</code></td>
|
||||
<td><?php _e('Purchase processing page', 'wp-digital-download'); ?></td>
|
||||
<td>
|
||||
<?php
|
||||
$checkout_page_id = get_option('wpdd_checkout_page_id');
|
||||
if ($checkout_page_id && get_post($checkout_page_id)) {
|
||||
echo '<span style="color: green;">✓ ' . __('Created', 'wp-digital-download') . '</span>';
|
||||
echo ' (<a href="' . get_edit_post_link($checkout_page_id) . '">' . __('Edit', 'wp-digital-download') . '</a>)';
|
||||
} else {
|
||||
echo '<span style="color: red;">✗ ' . __('Missing', 'wp-digital-download') . '</span>';
|
||||
}
|
||||
?>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong><?php _e('My Purchases', 'wp-digital-download'); ?></strong></td>
|
||||
<td><code>[wpdd_customer_purchases]</code></td>
|
||||
<td><?php _e('Customer purchase history', 'wp-digital-download'); ?></td>
|
||||
<td>
|
||||
<?php
|
||||
$purchases_page_id = get_option('wpdd_purchases_page_id');
|
||||
if ($purchases_page_id && get_post($purchases_page_id)) {
|
||||
echo '<span style="color: green;">✓ ' . __('Created', 'wp-digital-download') . '</span>';
|
||||
echo ' (<a href="' . get_edit_post_link($purchases_page_id) . '">' . __('Edit', 'wp-digital-download') . '</a>)';
|
||||
} else {
|
||||
echo '<span style="color: red;">✗ ' . __('Missing', 'wp-digital-download') . '</span>';
|
||||
}
|
||||
?>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong><?php _e('Thank You', 'wp-digital-download'); ?></strong></td>
|
||||
<td><code>[wpdd_thank_you]</code></td>
|
||||
<td><?php _e('Post-purchase confirmation', 'wp-digital-download'); ?></td>
|
||||
<td>
|
||||
<?php
|
||||
$thank_you_page_id = get_option('wpdd_thank_you_page_id');
|
||||
if ($thank_you_page_id && get_post($thank_you_page_id)) {
|
||||
echo '<span style="color: green;">✓ ' . __('Created', 'wp-digital-download') . '</span>';
|
||||
echo ' (<a href="' . get_edit_post_link($thank_you_page_id) . '">' . __('Edit', 'wp-digital-download') . '</a>)';
|
||||
} else {
|
||||
echo '<span style="color: red;">✗ ' . __('Missing', 'wp-digital-download') . '</span>';
|
||||
}
|
||||
?>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.wpdd-shortcodes-intro {
|
||||
background: #f1f1f1;
|
||||
padding: 15px;
|
||||
border-radius: 5px;
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
.wpdd-shortcodes-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(450px, 1fr));
|
||||
gap: 20px;
|
||||
margin: 30px 0;
|
||||
}
|
||||
|
||||
.wpdd-shortcode-card {
|
||||
background: #fff;
|
||||
border: 1px solid #ccd0d4;
|
||||
border-radius: 5px;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.wpdd-shortcode-card h3 {
|
||||
margin-top: 0;
|
||||
color: #23282d;
|
||||
border-bottom: 1px solid #eee;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.wpdd-shortcode-example {
|
||||
background: #f8f9fa;
|
||||
padding: 10px;
|
||||
border-radius: 3px;
|
||||
margin: 10px 0;
|
||||
font-family: monospace;
|
||||
border-left: 4px solid #2271b1;
|
||||
}
|
||||
|
||||
.wpdd-shortcode-examples {
|
||||
background: #f8f9fa;
|
||||
padding: 10px;
|
||||
border-radius: 3px;
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
.wpdd-shortcode-examples code {
|
||||
display: block;
|
||||
margin: 5px 0;
|
||||
color: #d63384;
|
||||
}
|
||||
|
||||
.wpdd-params-list {
|
||||
background: #fafafa;
|
||||
padding: 10px 30px;
|
||||
border-radius: 3px;
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
.wpdd-params-list li {
|
||||
margin: 8px 0;
|
||||
}
|
||||
|
||||
.wpdd-note {
|
||||
background: #fff3cd;
|
||||
border: 1px solid #ffeaa7;
|
||||
color: #856404;
|
||||
padding: 10px;
|
||||
border-radius: 3px;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.wpdd-page-setup {
|
||||
margin-top: 40px;
|
||||
padding-top: 30px;
|
||||
border-top: 2px solid #ddd;
|
||||
}
|
||||
|
||||
.wpdd-page-setup h2 {
|
||||
color: #23282d;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<?php
|
||||
}
|
||||
}
|
682
admin/class-wpdd-settings.php
Normal file
682
admin/class-wpdd-settings.php
Normal file
@@ -0,0 +1,682 @@
|
||||
<?php
|
||||
|
||||
if (!defined('ABSPATH')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
class WPDD_Settings {
|
||||
|
||||
public static function init() {
|
||||
add_action('admin_menu', array(__CLASS__, 'add_settings_page'));
|
||||
add_action('admin_init', array(__CLASS__, 'register_settings'));
|
||||
}
|
||||
|
||||
public static function add_settings_page() {
|
||||
add_submenu_page(
|
||||
'edit.php?post_type=wpdd_product',
|
||||
__('Settings', 'wp-digital-download'),
|
||||
__('Settings', 'wp-digital-download'),
|
||||
'wpdd_manage_settings',
|
||||
'wpdd-settings',
|
||||
array(__CLASS__, 'render_settings_page')
|
||||
);
|
||||
}
|
||||
|
||||
public static function register_settings() {
|
||||
register_setting('wpdd_settings', 'wpdd_paypal_mode');
|
||||
register_setting('wpdd_settings', 'wpdd_paypal_client_id');
|
||||
register_setting('wpdd_settings', 'wpdd_paypal_secret');
|
||||
register_setting('wpdd_settings', 'wpdd_admin_email');
|
||||
register_setting('wpdd_settings', 'wpdd_from_name');
|
||||
register_setting('wpdd_settings', 'wpdd_from_email');
|
||||
register_setting('wpdd_settings', 'wpdd_currency');
|
||||
register_setting('wpdd_settings', 'wpdd_enable_guest_checkout');
|
||||
register_setting('wpdd_settings', 'wpdd_default_download_limit');
|
||||
register_setting('wpdd_settings', 'wpdd_default_download_expiry');
|
||||
register_setting('wpdd_settings', 'wpdd_enable_watermark');
|
||||
register_setting('wpdd_settings', 'wpdd_watermark_text');
|
||||
register_setting('wpdd_settings', 'wpdd_terms_page');
|
||||
register_setting('wpdd_settings', 'wpdd_privacy_page');
|
||||
register_setting('wpdd_settings', 'wpdd_commission_rate', array(
|
||||
'sanitize_callback' => array(__CLASS__, 'sanitize_commission_rate')
|
||||
));
|
||||
register_setting('wpdd_settings', 'wpdd_payout_threshold', array(
|
||||
'sanitize_callback' => array(__CLASS__, 'sanitize_payout_threshold')
|
||||
));
|
||||
register_setting('wpdd_settings', 'wpdd_file_access_method');
|
||||
register_setting('wpdd_settings', 'wpdd_disable_admin_bar');
|
||||
|
||||
add_settings_section(
|
||||
'wpdd_general_settings',
|
||||
__('General Settings', 'wp-digital-download'),
|
||||
array(__CLASS__, 'general_section_callback'),
|
||||
'wpdd_settings'
|
||||
);
|
||||
|
||||
add_settings_section(
|
||||
'wpdd_paypal_settings',
|
||||
__('PayPal Settings', 'wp-digital-download'),
|
||||
array(__CLASS__, 'paypal_section_callback'),
|
||||
'wpdd_settings'
|
||||
);
|
||||
|
||||
add_settings_section(
|
||||
'wpdd_email_settings',
|
||||
__('Email Settings', 'wp-digital-download'),
|
||||
array(__CLASS__, 'email_section_callback'),
|
||||
'wpdd_settings'
|
||||
);
|
||||
|
||||
add_settings_section(
|
||||
'wpdd_download_settings',
|
||||
__('Download Settings', 'wp-digital-download'),
|
||||
array(__CLASS__, 'download_section_callback'),
|
||||
'wpdd_settings'
|
||||
);
|
||||
|
||||
add_settings_section(
|
||||
'wpdd_watermark_settings',
|
||||
__('Watermark Settings', 'wp-digital-download'),
|
||||
array(__CLASS__, 'watermark_section_callback'),
|
||||
'wpdd_settings'
|
||||
);
|
||||
|
||||
self::add_general_fields();
|
||||
self::add_paypal_fields();
|
||||
self::add_email_fields();
|
||||
self::add_download_fields();
|
||||
self::add_watermark_fields();
|
||||
}
|
||||
|
||||
private static function add_general_fields() {
|
||||
add_settings_field(
|
||||
'wpdd_currency',
|
||||
__('Currency', 'wp-digital-download'),
|
||||
array(__CLASS__, 'currency_field'),
|
||||
'wpdd_settings',
|
||||
'wpdd_general_settings',
|
||||
array(
|
||||
'name' => 'wpdd_currency'
|
||||
)
|
||||
);
|
||||
|
||||
add_settings_field(
|
||||
'wpdd_enable_guest_checkout',
|
||||
__('Guest Checkout', 'wp-digital-download'),
|
||||
array(__CLASS__, 'checkbox_field'),
|
||||
'wpdd_settings',
|
||||
'wpdd_general_settings',
|
||||
array(
|
||||
'name' => 'wpdd_enable_guest_checkout',
|
||||
'label' => __('Allow guest customers to purchase without creating an account', 'wp-digital-download')
|
||||
)
|
||||
);
|
||||
|
||||
add_settings_field(
|
||||
'wpdd_commission_rate',
|
||||
__('Platform Commission Rate (%)', 'wp-digital-download'),
|
||||
array(__CLASS__, 'number_field'),
|
||||
'wpdd_settings',
|
||||
'wpdd_general_settings',
|
||||
array(
|
||||
'name' => 'wpdd_commission_rate',
|
||||
'description' => __('Platform commission rate from sales (0-100). Creators receive the remainder.', 'wp-digital-download'),
|
||||
'min' => 0,
|
||||
'max' => 100,
|
||||
'step' => 0.01
|
||||
)
|
||||
);
|
||||
|
||||
add_settings_field(
|
||||
'wpdd_payout_threshold',
|
||||
__('Automatic Payout Threshold ($)', 'wp-digital-download'),
|
||||
array(__CLASS__, 'number_field'),
|
||||
'wpdd_settings',
|
||||
'wpdd_general_settings',
|
||||
array(
|
||||
'name' => 'wpdd_payout_threshold',
|
||||
'description' => __('Minimum balance for automatic payouts (0 to disable)', 'wp-digital-download'),
|
||||
'min' => 0,
|
||||
'step' => 0.01
|
||||
)
|
||||
);
|
||||
|
||||
add_settings_field(
|
||||
'wpdd_terms_page',
|
||||
__('Terms & Conditions Page', 'wp-digital-download'),
|
||||
array(__CLASS__, 'page_dropdown_field'),
|
||||
'wpdd_settings',
|
||||
'wpdd_general_settings',
|
||||
array('name' => 'wpdd_terms_page')
|
||||
);
|
||||
|
||||
add_settings_field(
|
||||
'wpdd_privacy_page',
|
||||
__('Privacy Policy Page', 'wp-digital-download'),
|
||||
array(__CLASS__, 'page_dropdown_field'),
|
||||
'wpdd_settings',
|
||||
'wpdd_general_settings',
|
||||
array('name' => 'wpdd_privacy_page')
|
||||
);
|
||||
}
|
||||
|
||||
private static function add_paypal_fields() {
|
||||
add_settings_field(
|
||||
'wpdd_paypal_mode',
|
||||
__('PayPal Mode', 'wp-digital-download'),
|
||||
array(__CLASS__, 'select_field'),
|
||||
'wpdd_settings',
|
||||
'wpdd_paypal_settings',
|
||||
array(
|
||||
'name' => 'wpdd_paypal_mode',
|
||||
'options' => array(
|
||||
'sandbox' => __('Sandbox (Testing)', 'wp-digital-download'),
|
||||
'live' => __('Live (Production)', 'wp-digital-download')
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
add_settings_field(
|
||||
'wpdd_paypal_client_id',
|
||||
__('PayPal Client ID', 'wp-digital-download'),
|
||||
array(__CLASS__, 'text_field'),
|
||||
'wpdd_settings',
|
||||
'wpdd_paypal_settings',
|
||||
array('name' => 'wpdd_paypal_client_id')
|
||||
);
|
||||
|
||||
add_settings_field(
|
||||
'wpdd_paypal_secret',
|
||||
__('PayPal Secret', 'wp-digital-download'),
|
||||
array(__CLASS__, 'password_field'),
|
||||
'wpdd_settings',
|
||||
'wpdd_paypal_settings',
|
||||
array('name' => 'wpdd_paypal_secret')
|
||||
);
|
||||
}
|
||||
|
||||
private static function add_email_fields() {
|
||||
add_settings_field(
|
||||
'wpdd_admin_email',
|
||||
__('Admin Email', 'wp-digital-download'),
|
||||
array(__CLASS__, 'email_field'),
|
||||
'wpdd_settings',
|
||||
'wpdd_email_settings',
|
||||
array(
|
||||
'name' => 'wpdd_admin_email',
|
||||
'description' => __('Email address for admin notifications', 'wp-digital-download')
|
||||
)
|
||||
);
|
||||
|
||||
add_settings_field(
|
||||
'wpdd_from_name',
|
||||
__('From Name', 'wp-digital-download'),
|
||||
array(__CLASS__, 'text_field'),
|
||||
'wpdd_settings',
|
||||
'wpdd_email_settings',
|
||||
array(
|
||||
'name' => 'wpdd_from_name',
|
||||
'description' => __('Name shown in email headers', 'wp-digital-download')
|
||||
)
|
||||
);
|
||||
|
||||
add_settings_field(
|
||||
'wpdd_from_email',
|
||||
__('From Email', 'wp-digital-download'),
|
||||
array(__CLASS__, 'email_field'),
|
||||
'wpdd_settings',
|
||||
'wpdd_email_settings',
|
||||
array(
|
||||
'name' => 'wpdd_from_email',
|
||||
'description' => __('Email address shown in email headers', 'wp-digital-download')
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private static function add_download_fields() {
|
||||
add_settings_field(
|
||||
'wpdd_default_download_limit',
|
||||
__('Default Download Limit', 'wp-digital-download'),
|
||||
array(__CLASS__, 'number_field'),
|
||||
'wpdd_settings',
|
||||
'wpdd_download_settings',
|
||||
array(
|
||||
'name' => 'wpdd_default_download_limit',
|
||||
'description' => __('Default number of downloads allowed per purchase (0 = unlimited)', 'wp-digital-download'),
|
||||
'min' => 0
|
||||
)
|
||||
);
|
||||
|
||||
add_settings_field(
|
||||
'wpdd_default_download_expiry',
|
||||
__('Default Download Expiry (days)', 'wp-digital-download'),
|
||||
array(__CLASS__, 'number_field'),
|
||||
'wpdd_settings',
|
||||
'wpdd_download_settings',
|
||||
array(
|
||||
'name' => 'wpdd_default_download_expiry',
|
||||
'description' => __('Default number of days downloads remain available (0 = never expires)', 'wp-digital-download'),
|
||||
'min' => 0
|
||||
)
|
||||
);
|
||||
|
||||
add_settings_field(
|
||||
'wpdd_file_access_method',
|
||||
__('File Access Method', 'wp-digital-download'),
|
||||
array(__CLASS__, 'select_field'),
|
||||
'wpdd_settings',
|
||||
'wpdd_download_settings',
|
||||
array(
|
||||
'name' => 'wpdd_file_access_method',
|
||||
'options' => array(
|
||||
'direct' => __('Direct Download', 'wp-digital-download'),
|
||||
'redirect' => __('Redirect to File', 'wp-digital-download'),
|
||||
'force' => __('Force Download', 'wp-digital-download')
|
||||
),
|
||||
'description' => __('How files are delivered to customers', 'wp-digital-download')
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private static function add_watermark_fields() {
|
||||
add_settings_field(
|
||||
'wpdd_enable_watermark',
|
||||
__('Enable Watermarking', 'wp-digital-download'),
|
||||
array(__CLASS__, 'checkbox_field'),
|
||||
'wpdd_settings',
|
||||
'wpdd_watermark_settings',
|
||||
array(
|
||||
'name' => 'wpdd_enable_watermark',
|
||||
'label' => __('Enable watermarking for images and PDFs by default', 'wp-digital-download')
|
||||
)
|
||||
);
|
||||
|
||||
add_settings_field(
|
||||
'wpdd_watermark_text',
|
||||
__('Default Watermark Text', 'wp-digital-download'),
|
||||
array(__CLASS__, 'text_field'),
|
||||
'wpdd_settings',
|
||||
'wpdd_watermark_settings',
|
||||
array(
|
||||
'name' => 'wpdd_watermark_text',
|
||||
'description' => __('Available placeholders: {customer_name}, {customer_email}, {order_id}, {date}, {site_name}', 'wp-digital-download')
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public static function render_settings_page() {
|
||||
?>
|
||||
<div class="wrap">
|
||||
<h1><?php _e('WP Digital Download Settings', 'wp-digital-download'); ?></h1>
|
||||
|
||||
<div class="wpdd-settings-sidebar">
|
||||
<div class="wpdd-settings-box">
|
||||
<h3><?php _e('Quick Setup', 'wp-digital-download'); ?></h3>
|
||||
<p><?php _e('To get started quickly:', 'wp-digital-download'); ?></p>
|
||||
<ol>
|
||||
<li><?php _e('Configure PayPal settings above', 'wp-digital-download'); ?></li>
|
||||
<li><?php _e('Create your first product', 'wp-digital-download'); ?></li>
|
||||
<li><?php _e('Add the shop shortcode [wpdd_shop] to a page', 'wp-digital-download'); ?></li>
|
||||
<li><?php _e('Test with a free product first', 'wp-digital-download'); ?></li>
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
<div class="wpdd-settings-box">
|
||||
<h3><?php _e('Available Shortcodes', 'wp-digital-download'); ?></h3>
|
||||
<ul>
|
||||
<li><code>[wpdd_shop]</code> - <?php _e('Display product storefront', 'wp-digital-download'); ?></li>
|
||||
<li><code>[wpdd_customer_purchases]</code> - <?php _e('Customer purchase history', 'wp-digital-download'); ?></li>
|
||||
<li><code>[wpdd_checkout]</code> - <?php _e('Checkout page', 'wp-digital-download'); ?></li>
|
||||
<li><code>[wpdd_thank_you]</code> - <?php _e('Thank you page', 'wp-digital-download'); ?></li>
|
||||
<li><code>[wpdd_product id="123"]</code> - <?php _e('Single product display', 'wp-digital-download'); ?></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="wpdd-settings-box">
|
||||
<h3><?php _e('System Status', 'wp-digital-download'); ?></h3>
|
||||
<?php self::system_status(); ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form method="post" action="options.php" class="wpdd-settings-form">
|
||||
<?php
|
||||
settings_fields('wpdd_settings');
|
||||
do_settings_sections('wpdd_settings');
|
||||
submit_button();
|
||||
?>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.wpdd-settings-sidebar {
|
||||
float: right;
|
||||
width: 300px;
|
||||
margin-left: 20px;
|
||||
position: relative;
|
||||
z-index: 10;
|
||||
}
|
||||
.wpdd-settings-form {
|
||||
overflow: hidden;
|
||||
margin-right: 340px;
|
||||
}
|
||||
.wpdd-settings-box {
|
||||
background: white;
|
||||
border: 1px solid #ccd0d4;
|
||||
padding: 20px;
|
||||
margin-bottom: 20px;
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,0.05);
|
||||
}
|
||||
.wpdd-settings-box h3 {
|
||||
margin-top: 0;
|
||||
}
|
||||
.wpdd-settings-box code {
|
||||
background: #f1f1f1;
|
||||
padding: 2px 5px;
|
||||
font-size: 12px;
|
||||
}
|
||||
.wpdd-status-good { color: #46b450; }
|
||||
.wpdd-status-warning { color: #ffb900; }
|
||||
.wpdd-status-error { color: #dc3232; }
|
||||
@media (max-width: 1200px) {
|
||||
.wpdd-settings-sidebar {
|
||||
float: none;
|
||||
width: 100%;
|
||||
margin-left: 0;
|
||||
margin-top: 30px;
|
||||
}
|
||||
.wpdd-settings-form {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<?php
|
||||
}
|
||||
|
||||
public static function general_section_callback() {
|
||||
echo '<p>' . __('Configure basic plugin settings.', 'wp-digital-download') . '</p>';
|
||||
}
|
||||
|
||||
public static function paypal_section_callback() {
|
||||
echo '<p>' . __('Configure PayPal payment settings. You can get your API credentials from the PayPal Developer Dashboard.', 'wp-digital-download') . '</p>';
|
||||
}
|
||||
|
||||
public static function email_section_callback() {
|
||||
echo '<p>' . __('Configure email settings for purchase notifications.', 'wp-digital-download') . '</p>';
|
||||
}
|
||||
|
||||
public static function download_section_callback() {
|
||||
echo '<p>' . __('Configure default download and file protection settings.', 'wp-digital-download') . '</p>';
|
||||
}
|
||||
|
||||
public static function watermark_section_callback() {
|
||||
echo '<p>' . __('Configure watermarking settings for images and PDF files.', 'wp-digital-download') . '</p>';
|
||||
}
|
||||
|
||||
public static function text_field($args) {
|
||||
$name = $args['name'] ?? '';
|
||||
$value = get_option($name, '');
|
||||
$description = isset($args['description']) ? $args['description'] : '';
|
||||
|
||||
if (empty($name)) {
|
||||
echo '<p>Error: Field name not provided</p>';
|
||||
return;
|
||||
}
|
||||
|
||||
printf(
|
||||
'<input type="text" id="%s" name="%s" value="%s" class="regular-text" />',
|
||||
esc_attr($name),
|
||||
esc_attr($name),
|
||||
esc_attr($value)
|
||||
);
|
||||
|
||||
if ($description) {
|
||||
printf('<p class="description">%s</p>', esc_html($description));
|
||||
}
|
||||
}
|
||||
|
||||
public static function password_field($args) {
|
||||
$name = $args['name'] ?? '';
|
||||
$value = get_option($name, '');
|
||||
$description = isset($args['description']) ? $args['description'] : '';
|
||||
|
||||
if (empty($name)) {
|
||||
echo '<p>Error: Field name not provided</p>';
|
||||
return;
|
||||
}
|
||||
|
||||
printf(
|
||||
'<input type="password" id="%s" name="%s" value="%s" class="regular-text" />',
|
||||
esc_attr($name),
|
||||
esc_attr($name),
|
||||
esc_attr($value)
|
||||
);
|
||||
|
||||
if ($description) {
|
||||
printf('<p class="description">%s</p>', esc_html($description));
|
||||
}
|
||||
}
|
||||
|
||||
public static function email_field($args) {
|
||||
$name = $args['name'] ?? '';
|
||||
$value = get_option($name, '');
|
||||
$description = isset($args['description']) ? $args['description'] : '';
|
||||
|
||||
if (empty($name)) {
|
||||
echo '<p>Error: Field name not provided</p>';
|
||||
return;
|
||||
}
|
||||
|
||||
printf(
|
||||
'<input type="email" id="%s" name="%s" value="%s" class="regular-text" />',
|
||||
esc_attr($name),
|
||||
esc_attr($name),
|
||||
esc_attr($value)
|
||||
);
|
||||
|
||||
if ($description) {
|
||||
printf('<p class="description">%s</p>', esc_html($description));
|
||||
}
|
||||
}
|
||||
|
||||
public static function number_field($args) {
|
||||
$name = $args['name'] ?? '';
|
||||
$value = get_option($name, '');
|
||||
$description = isset($args['description']) ? $args['description'] : '';
|
||||
$min = isset($args['min']) ? $args['min'] : 0;
|
||||
$max = isset($args['max']) ? $args['max'] : '';
|
||||
|
||||
if (empty($name)) {
|
||||
echo '<p>Error: Field name not provided</p>';
|
||||
return;
|
||||
}
|
||||
|
||||
printf(
|
||||
'<input type="number" id="%s" name="%s" value="%s" min="%s" %s />',
|
||||
esc_attr($name),
|
||||
esc_attr($name),
|
||||
esc_attr($value),
|
||||
esc_attr($min),
|
||||
$max ? 'max="' . esc_attr($max) . '"' : ''
|
||||
);
|
||||
|
||||
if ($description) {
|
||||
printf('<p class="description">%s</p>', esc_html($description));
|
||||
}
|
||||
}
|
||||
|
||||
public static function checkbox_field($args) {
|
||||
$name = $args['name'] ?? '';
|
||||
$value = get_option($name, 0);
|
||||
$label = $args['label'] ?? '';
|
||||
|
||||
if (empty($name)) {
|
||||
echo '<p>Error: Field name not provided</p>';
|
||||
return;
|
||||
}
|
||||
|
||||
printf(
|
||||
'<label><input type="checkbox" id="%s" name="%s" value="1" %s /> %s</label>',
|
||||
esc_attr($name),
|
||||
esc_attr($name),
|
||||
checked($value, 1, false),
|
||||
esc_html($label)
|
||||
);
|
||||
}
|
||||
|
||||
public static function select_field($args) {
|
||||
$name = $args['name'] ?? '';
|
||||
$value = get_option($name, '');
|
||||
$options = $args['options'] ?? array();
|
||||
$description = isset($args['description']) ? $args['description'] : '';
|
||||
|
||||
if (empty($name)) {
|
||||
echo '<p>Error: Field name not provided</p>';
|
||||
return;
|
||||
}
|
||||
|
||||
printf('<select id="%s" name="%s">', esc_attr($name), esc_attr($name));
|
||||
|
||||
foreach ($options as $option_value => $option_label) {
|
||||
printf(
|
||||
'<option value="%s" %s>%s</option>',
|
||||
esc_attr($option_value),
|
||||
selected($value, $option_value, false),
|
||||
esc_html($option_label)
|
||||
);
|
||||
}
|
||||
|
||||
echo '</select>';
|
||||
|
||||
if ($description) {
|
||||
printf('<p class="description">%s</p>', esc_html($description));
|
||||
}
|
||||
}
|
||||
|
||||
public static function currency_field($args) {
|
||||
$currencies = array(
|
||||
'USD' => 'US Dollar ($)',
|
||||
'EUR' => 'Euro (€)',
|
||||
'GBP' => 'British Pound (£)',
|
||||
'CAD' => 'Canadian Dollar (C$)',
|
||||
'AUD' => 'Australian Dollar (A$)',
|
||||
'JPY' => 'Japanese Yen (¥)'
|
||||
);
|
||||
|
||||
$args['options'] = $currencies;
|
||||
self::select_field($args);
|
||||
}
|
||||
|
||||
public static function page_dropdown_field($args) {
|
||||
$name = $args['name'] ?? '';
|
||||
$value = get_option($name, '');
|
||||
|
||||
if (empty($name)) {
|
||||
echo '<p>Error: Field name not provided</p>';
|
||||
return;
|
||||
}
|
||||
|
||||
wp_dropdown_pages(array(
|
||||
'name' => $name,
|
||||
'id' => $name,
|
||||
'selected' => $value,
|
||||
'show_option_none' => __('— Select —', 'wp-digital-download'),
|
||||
'option_none_value' => ''
|
||||
));
|
||||
}
|
||||
|
||||
private static function system_status() {
|
||||
$status = array();
|
||||
|
||||
$upload_dir = wp_upload_dir();
|
||||
$protected_dir = trailingslashit($upload_dir['basedir']) . WPDD_UPLOADS_DIR;
|
||||
|
||||
if (is_writable($upload_dir['basedir'])) {
|
||||
$status[] = array(
|
||||
'label' => __('Upload Directory', 'wp-digital-download'),
|
||||
'value' => __('Writable', 'wp-digital-download'),
|
||||
'class' => 'wpdd-status-good'
|
||||
);
|
||||
} else {
|
||||
$status[] = array(
|
||||
'label' => __('Upload Directory', 'wp-digital-download'),
|
||||
'value' => __('Not Writable', 'wp-digital-download'),
|
||||
'class' => 'wpdd-status-error'
|
||||
);
|
||||
}
|
||||
|
||||
if (file_exists($protected_dir)) {
|
||||
$status[] = array(
|
||||
'label' => __('Protected Directory', 'wp-digital-download'),
|
||||
'value' => __('Exists', 'wp-digital-download'),
|
||||
'class' => 'wpdd-status-good'
|
||||
);
|
||||
} else {
|
||||
$status[] = array(
|
||||
'label' => __('Protected Directory', 'wp-digital-download'),
|
||||
'value' => __('Missing', 'wp-digital-download'),
|
||||
'class' => 'wpdd-status-warning'
|
||||
);
|
||||
}
|
||||
|
||||
if (function_exists('imagecreatefrompng')) {
|
||||
$status[] = array(
|
||||
'label' => __('GD Library', 'wp-digital-download'),
|
||||
'value' => __('Available', 'wp-digital-download'),
|
||||
'class' => 'wpdd-status-good'
|
||||
);
|
||||
} else {
|
||||
$status[] = array(
|
||||
'label' => __('GD Library', 'wp-digital-download'),
|
||||
'value' => __('Not Available', 'wp-digital-download'),
|
||||
'class' => 'wpdd-status-warning'
|
||||
);
|
||||
}
|
||||
|
||||
$paypal_client_id = get_option('wpdd_paypal_client_id');
|
||||
if ($paypal_client_id) {
|
||||
$status[] = array(
|
||||
'label' => __('PayPal', 'wp-digital-download'),
|
||||
'value' => __('Configured', 'wp-digital-download'),
|
||||
'class' => 'wpdd-status-good'
|
||||
);
|
||||
} else {
|
||||
$status[] = array(
|
||||
'label' => __('PayPal', 'wp-digital-download'),
|
||||
'value' => __('Not Configured', 'wp-digital-download'),
|
||||
'class' => 'wpdd-status-warning'
|
||||
);
|
||||
}
|
||||
|
||||
echo '<ul>';
|
||||
foreach ($status as $item) {
|
||||
printf(
|
||||
'<li>%s: <span class="%s">%s</span></li>',
|
||||
esc_html($item['label']),
|
||||
esc_attr($item['class']),
|
||||
esc_html($item['value'])
|
||||
);
|
||||
}
|
||||
echo '</ul>';
|
||||
}
|
||||
|
||||
public static function sanitize_commission_rate($input) {
|
||||
$value = floatval($input);
|
||||
if ($value < 0) {
|
||||
$value = 0;
|
||||
add_settings_error('wpdd_commission_rate', 'invalid_rate', __('Commission rate cannot be less than 0%. Set to 0%.', 'wp-digital-download'));
|
||||
} elseif ($value > 100) {
|
||||
$value = 100;
|
||||
add_settings_error('wpdd_commission_rate', 'invalid_rate', __('Commission rate cannot exceed 100%. Set to 100%.', 'wp-digital-download'));
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
public static function sanitize_payout_threshold($input) {
|
||||
$value = floatval($input);
|
||||
if ($value < 0) {
|
||||
$value = 0;
|
||||
add_settings_error('wpdd_payout_threshold', 'invalid_threshold', __('Payout threshold cannot be negative. Set to 0 (disabled).', 'wp-digital-download'));
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user