Some checks failed
Create Release / build (push) Failing after 3s
🔧 Bug Fixes: - Fixed download limits defaulting to 5 instead of 0 for unlimited downloads - Fixed software license filename sanitization (spaces→dashes, dots→underscores, proper .zip extension) - Software downloads now show as "Test-Plugin-v2-2-0.zip" instead of "Test Plugin v2.2.0" ✨ UI/UX Enhancements: - Redesigned license key display to span full table width with FontAwesome copy icons - Added responsive CSS styling for license key rows - Integrated FontAwesome CDN for modern copy icons 🏗️ Architecture Improvements: - Added comprehensive filename sanitization in both download handler and API paths - Enhanced software license product handling for local package files - Improved error handling and logging throughout download processes 📦 Infrastructure: - Added Gitea workflows for automated releases on push to main - Created comprehensive .gitignore excluding test files and browser automation - Updated documentation with all recent improvements and technical insights 🔍 Technical Details: - Software license products served from wp-content/uploads/wpdd-packages/ - Download flow: token → process_download_by_token() → process_download() → deliver_file() - Dual path coverage for both API downloads and regular file delivery - Version placeholder system for automated deployment 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
1187 lines
55 KiB
PHP
1187 lines
55 KiB
PHP
<?php
|
|
|
|
if (!defined('ABSPATH')) {
|
|
exit;
|
|
}
|
|
|
|
class WPDD_Shortcodes {
|
|
|
|
public static function init() {
|
|
add_shortcode('wpdd_shop', array(__CLASS__, 'shop_shortcode'));
|
|
add_shortcode('wpdd_customer_purchases', array(__CLASS__, 'customer_purchases_shortcode'));
|
|
add_shortcode('wpdd_checkout', array(__CLASS__, 'checkout_shortcode'));
|
|
add_shortcode('wpdd_thank_you', array(__CLASS__, 'thank_you_shortcode'));
|
|
add_shortcode('wpdd_product', array(__CLASS__, 'single_product_shortcode'));
|
|
add_shortcode('wpdd_buy_button', array(__CLASS__, 'buy_button_shortcode'));
|
|
add_shortcode('wpdd_creator_dashboard', array(__CLASS__, 'creator_dashboard_shortcode'));
|
|
|
|
// Add buy button to single product pages automatically
|
|
add_filter('the_content', array(__CLASS__, 'add_buy_button_to_product'));
|
|
}
|
|
|
|
public static function shop_shortcode($atts) {
|
|
$atts = shortcode_atts(array(
|
|
'columns' => 3,
|
|
'per_page' => 12,
|
|
'category' => '',
|
|
'orderby' => 'date',
|
|
'order' => 'DESC',
|
|
'show_filters' => 'yes'
|
|
), $atts);
|
|
|
|
ob_start();
|
|
|
|
$paged = (get_query_var('paged')) ? get_query_var('paged') : 1;
|
|
|
|
$args = array(
|
|
'post_type' => 'wpdd_product',
|
|
'posts_per_page' => $atts['per_page'],
|
|
'paged' => $paged,
|
|
'orderby' => $atts['orderby'],
|
|
'order' => $atts['order'],
|
|
'post_status' => 'publish'
|
|
);
|
|
|
|
if (!empty($atts['category'])) {
|
|
$args['tax_query'] = array(
|
|
array(
|
|
'taxonomy' => 'wpdd_product_category',
|
|
'field' => 'slug',
|
|
'terms' => explode(',', $atts['category'])
|
|
)
|
|
);
|
|
}
|
|
|
|
// Handle search
|
|
$search_performed = false;
|
|
if (isset($_GET['wpdd_search']) && !empty($_GET['wpdd_search'])) {
|
|
$search_term = sanitize_text_field($_GET['wpdd_search']);
|
|
$search_performed = true;
|
|
|
|
// Bypass WordPress search and do direct query
|
|
global $wpdb;
|
|
$search_like = '%' . $wpdb->esc_like($search_term) . '%';
|
|
|
|
$matching_ids = $wpdb->get_col($wpdb->prepare(
|
|
"SELECT ID FROM {$wpdb->posts}
|
|
WHERE post_type = 'wpdd_product'
|
|
AND post_status = 'publish'
|
|
AND (post_title LIKE %s OR post_content LIKE %s)",
|
|
$search_like,
|
|
$search_like
|
|
));
|
|
|
|
// Add debug output
|
|
if (current_user_can('manage_options')) {
|
|
echo "<!-- DEBUG: Search for '$search_term' found IDs: " . implode(', ', $matching_ids) . " -->";
|
|
}
|
|
|
|
if (!empty($matching_ids)) {
|
|
// Found matching products
|
|
$args['post__in'] = $matching_ids;
|
|
// Only set orderby to post__in if no sort parameter is provided
|
|
if (!isset($_GET['wpdd_sort']) || empty($_GET['wpdd_sort'])) {
|
|
$args['orderby'] = 'post__in';
|
|
}
|
|
} else {
|
|
// No matches - force empty result
|
|
$args['post__in'] = array(-1); // Use -1 instead of 0
|
|
}
|
|
}
|
|
|
|
if (isset($_GET['wpdd_category']) && !empty($_GET['wpdd_category'])) {
|
|
$args['tax_query'] = array(
|
|
array(
|
|
'taxonomy' => 'wpdd_product_category',
|
|
'field' => 'slug',
|
|
'terms' => sanitize_text_field($_GET['wpdd_category'])
|
|
)
|
|
);
|
|
}
|
|
|
|
// Handle creator filter
|
|
if (isset($_GET['wpdd_creator']) && !empty($_GET['wpdd_creator'])) {
|
|
$args['author'] = intval($_GET['wpdd_creator']);
|
|
}
|
|
|
|
if (isset($_GET['wpdd_sort']) && !empty($_GET['wpdd_sort'])) {
|
|
switch ($_GET['wpdd_sort']) {
|
|
case 'price_low':
|
|
$args['meta_key'] = '_wpdd_price';
|
|
$args['orderby'] = 'meta_value_num';
|
|
$args['order'] = 'ASC';
|
|
break;
|
|
case 'price_high':
|
|
$args['meta_key'] = '_wpdd_price';
|
|
$args['orderby'] = 'meta_value_num';
|
|
$args['order'] = 'DESC';
|
|
break;
|
|
case 'newest':
|
|
$args['orderby'] = 'date';
|
|
$args['order'] = 'DESC';
|
|
break;
|
|
case 'popular':
|
|
$args['meta_key'] = '_wpdd_sales_count';
|
|
$args['orderby'] = 'meta_value_num';
|
|
$args['order'] = 'DESC';
|
|
break;
|
|
}
|
|
}
|
|
|
|
$query = new WP_Query($args);
|
|
|
|
// Debug output for admins
|
|
if (current_user_can('manage_options') && isset($_GET['debug']) && $_GET['debug'] == '1') {
|
|
echo '<div style="background: #fff; border: 1px solid #ccc; padding: 10px; margin: 10px 0;">';
|
|
echo '<h4>Debug Info (Admin Only)</h4>';
|
|
echo '<strong>GET Parameters:</strong><br>' . print_r($_GET, true) . '<br>';
|
|
echo '<strong>Query Args:</strong><br>' . print_r($args, true) . '<br>';
|
|
echo '<strong>Found Posts:</strong> ' . $query->found_posts . '<br>';
|
|
echo '</div>';
|
|
}
|
|
?>
|
|
|
|
<div class="wpdd-shop-container">
|
|
<?php if ($atts['show_filters'] === 'yes') : ?>
|
|
<div class="wpdd-shop-filters">
|
|
<form method="get" class="wpdd-filter-form">
|
|
<?php
|
|
// Preserve other query parameters but exclude filter and pagination params
|
|
$query_args = $_GET;
|
|
|
|
// Add hidden fields for non-filter params
|
|
foreach ($query_args as $key => $value) {
|
|
if (!in_array($key, array('wpdd_search', 'wpdd_category', 'wpdd_creator', 'wpdd_sort', 'paged'))) {
|
|
if (is_array($value)) {
|
|
foreach ($value as $sub_value) {
|
|
echo '<input type="hidden" name="' . esc_attr($key) . '[]" value="' . esc_attr($sub_value) . '" />';
|
|
}
|
|
} else {
|
|
echo '<input type="hidden" name="' . esc_attr($key) . '" value="' . esc_attr($value) . '" />';
|
|
}
|
|
}
|
|
}
|
|
?>
|
|
<div class="wpdd-filter-row">
|
|
<input type="text" name="wpdd_search"
|
|
placeholder="<?php _e('Search products...', 'wp-digital-download'); ?>"
|
|
value="<?php echo isset($_GET['wpdd_search']) ? esc_attr($_GET['wpdd_search']) : ''; ?>" />
|
|
|
|
<select name="wpdd_category">
|
|
<option value=""><?php _e('All Categories', 'wp-digital-download'); ?></option>
|
|
<?php
|
|
$categories = get_terms(array(
|
|
'taxonomy' => 'wpdd_product_category',
|
|
'hide_empty' => true
|
|
));
|
|
|
|
if (!is_wp_error($categories) && !empty($categories)) {
|
|
foreach ($categories as $category) {
|
|
printf(
|
|
'<option value="%s" %s>%s</option>',
|
|
esc_attr($category->slug),
|
|
selected(isset($_GET['wpdd_category']) && $_GET['wpdd_category'] == $category->slug, true, false),
|
|
esc_html($category->name)
|
|
);
|
|
}
|
|
}
|
|
?>
|
|
</select>
|
|
|
|
<select name="wpdd_sort">
|
|
<option value=""><?php _e('Default sorting', 'wp-digital-download'); ?></option>
|
|
<option value="newest" <?php selected(isset($_GET['wpdd_sort']) && $_GET['wpdd_sort'] == 'newest'); ?>>
|
|
<?php _e('Newest first', 'wp-digital-download'); ?>
|
|
</option>
|
|
<option value="price_low" <?php selected(isset($_GET['wpdd_sort']) && $_GET['wpdd_sort'] == 'price_low'); ?>>
|
|
<?php _e('Price: Low to High', 'wp-digital-download'); ?>
|
|
</option>
|
|
<option value="price_high" <?php selected(isset($_GET['wpdd_sort']) && $_GET['wpdd_sort'] == 'price_high'); ?>>
|
|
<?php _e('Price: High to Low', 'wp-digital-download'); ?>
|
|
</option>
|
|
<option value="popular" <?php selected(isset($_GET['wpdd_sort']) && $_GET['wpdd_sort'] == 'popular'); ?>>
|
|
<?php _e('Most Popular', 'wp-digital-download'); ?>
|
|
</option>
|
|
</select>
|
|
|
|
<button type="submit" class="wpdd-filter-submit">
|
|
<?php _e('Filter', 'wp-digital-download'); ?>
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<?php if ($query->have_posts()) : ?>
|
|
<div class="wpdd-products-grid wpdd-columns-<?php echo esc_attr($atts['columns']); ?>">
|
|
<?php while ($query->have_posts()) : $query->the_post(); ?>
|
|
<?php self::render_product_card(get_the_ID()); ?>
|
|
<?php endwhile; ?>
|
|
</div>
|
|
|
|
<div class="wpdd-pagination">
|
|
<?php
|
|
// Build pagination URL with current filter parameters
|
|
$pagination_args = array();
|
|
if (isset($_GET['wpdd_search']) && $_GET['wpdd_search']) {
|
|
$pagination_args['wpdd_search'] = $_GET['wpdd_search'];
|
|
}
|
|
if (isset($_GET['wpdd_category']) && $_GET['wpdd_category']) {
|
|
$pagination_args['wpdd_category'] = $_GET['wpdd_category'];
|
|
}
|
|
if (isset($_GET['wpdd_creator']) && $_GET['wpdd_creator']) {
|
|
$pagination_args['wpdd_creator'] = $_GET['wpdd_creator'];
|
|
}
|
|
if (isset($_GET['wpdd_sort']) && $_GET['wpdd_sort']) {
|
|
$pagination_args['wpdd_sort'] = $_GET['wpdd_sort'];
|
|
}
|
|
|
|
$base_url = get_permalink();
|
|
if (!empty($pagination_args)) {
|
|
$base_url = add_query_arg($pagination_args, $base_url);
|
|
$base_url = add_query_arg('paged', '%#%', $base_url);
|
|
} else {
|
|
$base_url = add_query_arg('paged', '%#%', $base_url);
|
|
}
|
|
|
|
echo paginate_links(array(
|
|
'base' => $base_url,
|
|
'total' => $query->max_num_pages,
|
|
'current' => $paged,
|
|
'format' => '',
|
|
'prev_text' => __('« Previous', 'wp-digital-download'),
|
|
'next_text' => __('Next »', 'wp-digital-download'),
|
|
));
|
|
?>
|
|
</div>
|
|
<?php else : ?>
|
|
<p class="wpdd-no-products">
|
|
<?php _e('No products found.', 'wp-digital-download'); ?>
|
|
</p>
|
|
<?php endif; ?>
|
|
|
|
<?php wp_reset_postdata(); ?>
|
|
</div>
|
|
|
|
<?php
|
|
return ob_get_clean();
|
|
}
|
|
|
|
private static function render_product_card($product_id) {
|
|
$product = get_post($product_id);
|
|
$price = get_post_meta($product_id, '_wpdd_price', true);
|
|
$sale_price = get_post_meta($product_id, '_wpdd_sale_price', true);
|
|
$is_free = get_post_meta($product_id, '_wpdd_is_free', true);
|
|
$creator = get_userdata($product->post_author);
|
|
?>
|
|
<div class="wpdd-product-card">
|
|
<div class="wpdd-product-image">
|
|
<?php if (has_post_thumbnail($product_id)) : ?>
|
|
<a href="<?php echo get_permalink($product_id); ?>">
|
|
<?php echo get_the_post_thumbnail($product_id, 'medium'); ?>
|
|
</a>
|
|
<?php else : ?>
|
|
<a href="<?php echo get_permalink($product_id); ?>">
|
|
<img src="<?php echo WPDD_PLUGIN_URL; ?>assets/images/placeholder.png"
|
|
alt="<?php echo esc_attr($product->post_title); ?>" />
|
|
</a>
|
|
<?php endif; ?>
|
|
</div>
|
|
|
|
<div class="wpdd-product-info">
|
|
<h3 class="wpdd-product-title">
|
|
<a href="<?php echo get_permalink($product_id); ?>">
|
|
<?php echo esc_html($product->post_title); ?>
|
|
</a>
|
|
</h3>
|
|
|
|
<div class="wpdd-product-meta">
|
|
<span class="wpdd-product-creator">
|
|
<?php _e('by', 'wp-digital-download'); ?>
|
|
<?php
|
|
$shop_page_id = get_option('wpdd_shop_page_id');
|
|
$shop_url = $shop_page_id ? get_permalink($shop_page_id) : home_url('/shop/');
|
|
$creator_filter_url = add_query_arg('wpdd_creator', $creator->ID, $shop_url);
|
|
?>
|
|
<a href="<?php echo esc_url($creator_filter_url); ?>"><?php echo esc_html($creator->display_name); ?></a>
|
|
</span>
|
|
</div>
|
|
|
|
<div class="wpdd-product-excerpt">
|
|
<?php echo wp_trim_words($product->post_excerpt ?: $product->post_content, 20); ?>
|
|
</div>
|
|
|
|
<div class="wpdd-product-price">
|
|
<?php if ($is_free) : ?>
|
|
<span class="wpdd-price-free"><?php _e('Free', 'wp-digital-download'); ?></span>
|
|
<?php elseif ($sale_price && $sale_price < $price) : ?>
|
|
<span class="wpdd-price-regular wpdd-price-strike">$<?php echo number_format($price, 2); ?></span>
|
|
<span class="wpdd-price-sale">$<?php echo number_format($sale_price, 2); ?></span>
|
|
<?php else : ?>
|
|
<span class="wpdd-price-regular">$<?php echo number_format($price, 2); ?></span>
|
|
<?php endif; ?>
|
|
</div>
|
|
|
|
<div class="wpdd-product-actions">
|
|
<a href="<?php echo get_permalink($product_id); ?>" class="wpdd-btn wpdd-btn-view">
|
|
<?php _e('View Details', 'wp-digital-download'); ?>
|
|
</a>
|
|
<?php
|
|
if ($is_free) {
|
|
$button_text = __('Free Download', 'wp-digital-download');
|
|
} else {
|
|
$actual_price = ($sale_price && $sale_price < $price) ? $sale_price : $price;
|
|
$button_text = sprintf(__('Buy - $%s', 'wp-digital-download'), number_format($actual_price, 2));
|
|
}
|
|
echo self::render_buy_button($product_id, $button_text, 'wpdd-btn wpdd-btn-buy');
|
|
?>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<?php
|
|
}
|
|
|
|
public static function customer_purchases_shortcode($atts) {
|
|
global $wpdb;
|
|
|
|
// Check if viewing by email (for guest purchases)
|
|
if (isset($_GET['customer_email']) && isset($_GET['key'])) {
|
|
$email = sanitize_email($_GET['customer_email']);
|
|
$key = sanitize_text_field($_GET['key']);
|
|
|
|
// Verify the key (simple hash check)
|
|
$expected_key = substr(md5($email . AUTH_KEY), 0, 10);
|
|
if ($key !== $expected_key) {
|
|
return '<p class="wpdd-error">' . __('Invalid access key.', 'wp-digital-download') . '</p>';
|
|
}
|
|
|
|
$orders = $wpdb->get_results($wpdb->prepare(
|
|
"SELECT o.*, p.post_title as product_name, l.license_key,
|
|
(SELECT COUNT(*) FROM {$wpdb->prefix}wpdd_downloads d WHERE d.order_id = o.id) as download_count
|
|
FROM {$wpdb->prefix}wpdd_orders o
|
|
LEFT JOIN {$wpdb->posts} p ON o.product_id = p.ID
|
|
LEFT JOIN {$wpdb->prefix}wpdd_licenses l ON o.id = l.order_id
|
|
WHERE o.customer_email = %s
|
|
AND o.status = 'completed'
|
|
ORDER BY o.purchase_date DESC",
|
|
$email
|
|
));
|
|
|
|
} elseif (is_user_logged_in()) {
|
|
$current_user = wp_get_current_user();
|
|
|
|
// Get orders by user ID or email (to include guest purchases before account creation)
|
|
$orders = $wpdb->get_results($wpdb->prepare(
|
|
"SELECT o.*, p.post_title as product_name, l.license_key,
|
|
(SELECT COUNT(*) FROM {$wpdb->prefix}wpdd_downloads d WHERE d.order_id = o.id) as download_count
|
|
FROM {$wpdb->prefix}wpdd_orders o
|
|
LEFT JOIN {$wpdb->posts} p ON o.product_id = p.ID
|
|
LEFT JOIN {$wpdb->prefix}wpdd_licenses l ON o.id = l.order_id
|
|
WHERE (o.customer_id = %d OR o.customer_email = %s)
|
|
AND o.status = 'completed'
|
|
ORDER BY o.purchase_date DESC",
|
|
$current_user->ID,
|
|
$current_user->user_email
|
|
));
|
|
|
|
} else {
|
|
return '<p class="wpdd-login-required">' .
|
|
sprintf(
|
|
__('Please <a href="%s">login</a> to view your purchases.', 'wp-digital-download'),
|
|
wp_login_url(get_permalink())
|
|
) . '</p>';
|
|
}
|
|
|
|
ob_start();
|
|
?>
|
|
<div class="wpdd-customer-purchases">
|
|
<h2><?php _e('My Purchases', 'wp-digital-download'); ?></h2>
|
|
|
|
<?php if ($orders) : ?>
|
|
<table class="wpdd-purchases-table">
|
|
<thead>
|
|
<tr>
|
|
<th><?php _e('Order #', 'wp-digital-download'); ?></th>
|
|
<th><?php _e('Product', 'wp-digital-download'); ?></th>
|
|
<th><?php _e('Purchase Date', 'wp-digital-download'); ?></th>
|
|
<th><?php _e('Amount', 'wp-digital-download'); ?></th>
|
|
<th><?php _e('Downloads', 'wp-digital-download'); ?></th>
|
|
<th><?php _e('Actions', 'wp-digital-download'); ?></th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php foreach ($orders as $order) : ?>
|
|
<?php
|
|
$download_limit = get_post_meta($order->product_id, '_wpdd_download_limit', true);
|
|
$download_limit = $download_limit ?: 0; // Convert empty string to 0 (unlimited)
|
|
$download_expiry = get_post_meta($order->product_id, '_wpdd_download_expiry', true);
|
|
$is_expired = false;
|
|
|
|
if ($download_expiry > 0) {
|
|
$expiry_date = date('Y-m-d H:i:s', strtotime($order->purchase_date . ' + ' . $download_expiry . ' days'));
|
|
$is_expired = current_time('mysql') > $expiry_date;
|
|
}
|
|
|
|
// Ensure download_count is a number
|
|
$current_downloads = (int) $order->download_count;
|
|
$can_download = !$is_expired && ($download_limit == 0 || $current_downloads < $download_limit);
|
|
?>
|
|
<tr>
|
|
<td><?php echo esc_html($order->order_number); ?></td>
|
|
<td>
|
|
<a href="<?php echo get_permalink($order->product_id); ?>">
|
|
<?php echo esc_html($order->product_name); ?>
|
|
</a>
|
|
</td>
|
|
<td><?php echo date_i18n(get_option('date_format'), strtotime($order->purchase_date)); ?></td>
|
|
<td>$<?php echo number_format($order->amount, 2); ?></td>
|
|
<td>
|
|
<?php
|
|
if ($download_limit > 0) {
|
|
echo sprintf('%d / %d', $current_downloads, $download_limit);
|
|
} else {
|
|
echo sprintf('%d / %s', $current_downloads, __('unlimited', 'wp-digital-download'));
|
|
}
|
|
?>
|
|
</td>
|
|
<td>
|
|
<?php if ($can_download) : ?>
|
|
<?php
|
|
// Build download URL with appropriate parameters
|
|
$download_args = array('wpdd_download' => $order->id);
|
|
|
|
// For guest access, include email and key
|
|
if (isset($_GET['customer_email']) && isset($_GET['key'])) {
|
|
$download_args['customer_email'] = $_GET['customer_email'];
|
|
$download_args['key'] = $_GET['key'];
|
|
}
|
|
|
|
$download_url = wp_nonce_url(
|
|
add_query_arg($download_args),
|
|
'wpdd_download_' . $order->id
|
|
);
|
|
?>
|
|
<a href="<?php echo esc_url($download_url); ?>" class="wpdd-btn wpdd-btn-download">
|
|
<?php _e('Download', 'wp-digital-download'); ?>
|
|
</a>
|
|
<?php else : ?>
|
|
<span class="wpdd-download-expired">
|
|
<?php
|
|
if ($is_expired) {
|
|
_e('Expired', 'wp-digital-download');
|
|
} else {
|
|
_e('Limit Reached', 'wp-digital-download');
|
|
}
|
|
?>
|
|
</span>
|
|
<?php endif; ?>
|
|
</td>
|
|
</tr>
|
|
<?php if (!empty($order->license_key)) : ?>
|
|
<tr class="wpdd-license-row">
|
|
<td colspan="6" class="wpdd-license-cell">
|
|
<div class="wpdd-license-info">
|
|
<small><?php _e('License Key:', 'wp-digital-download'); ?></small>
|
|
<code class="wpdd-license-key"><?php echo esc_html($order->license_key); ?></code>
|
|
<button type="button" class="wpdd-copy-license" data-license="<?php echo esc_attr($order->license_key); ?>" title="<?php _e('Copy to clipboard', 'wp-digital-download'); ?>">
|
|
<i class="fas fa-copy"></i>
|
|
</button>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<?php endif; ?>
|
|
<?php endforeach; ?>
|
|
</tbody>
|
|
</table>
|
|
<?php else : ?>
|
|
<p><?php _e('You have not purchased any products yet.', 'wp-digital-download'); ?></p>
|
|
<p><a href="<?php echo get_option('wpdd_shop_page_id') ? get_permalink(get_option('wpdd_shop_page_id')) : home_url(); ?>"
|
|
class="wpdd-btn wpdd-btn-primary">
|
|
<?php _e('Browse Products', 'wp-digital-download'); ?>
|
|
</a></p>
|
|
<?php endif; ?>
|
|
</div>
|
|
<?php
|
|
return ob_get_clean();
|
|
}
|
|
|
|
public static function checkout_shortcode($atts) {
|
|
if (!isset($_GET['product_id'])) {
|
|
return '<p>' . __('No product selected for checkout.', 'wp-digital-download') . '</p>';
|
|
}
|
|
|
|
$product_id = intval($_GET['product_id']);
|
|
$product = get_post($product_id);
|
|
|
|
if (!$product || $product->post_type !== 'wpdd_product') {
|
|
return '<p>' . __('Invalid product.', 'wp-digital-download') . '</p>';
|
|
}
|
|
|
|
$price = get_post_meta($product_id, '_wpdd_price', true);
|
|
$sale_price = get_post_meta($product_id, '_wpdd_sale_price', true);
|
|
$is_free = get_post_meta($product_id, '_wpdd_is_free', true);
|
|
$final_price = ($sale_price && $sale_price < $price) ? $sale_price : $price;
|
|
|
|
ob_start();
|
|
?>
|
|
<div class="wpdd-checkout">
|
|
<h2><?php _e('Checkout', 'wp-digital-download'); ?></h2>
|
|
|
|
<div class="wpdd-checkout-product">
|
|
<h3><?php echo esc_html($product->post_title); ?></h3>
|
|
<?php if (has_post_thumbnail($product_id)) : ?>
|
|
<?php echo get_the_post_thumbnail($product_id, 'thumbnail'); ?>
|
|
<?php endif; ?>
|
|
<div class="wpdd-checkout-price">
|
|
<?php if ($is_free) : ?>
|
|
<span><?php _e('Free', 'wp-digital-download'); ?></span>
|
|
<?php else : ?>
|
|
<span><?php _e('Total:', 'wp-digital-download'); ?> $<?php echo number_format($final_price, 2); ?></span>
|
|
<?php endif; ?>
|
|
</div>
|
|
</div>
|
|
|
|
<form id="wpdd-checkout-form" method="post" data-product-free="<?php echo $is_free ? '1' : '0'; ?>">
|
|
<?php wp_nonce_field('wpdd_checkout', 'wpdd_checkout_nonce'); ?>
|
|
<input type="hidden" name="product_id" value="<?php echo $product_id; ?>" />
|
|
|
|
<?php if (!is_user_logged_in()) : ?>
|
|
<div class="wpdd-checkout-section">
|
|
<h4><?php _e('Customer Information', 'wp-digital-download'); ?></h4>
|
|
|
|
<p>
|
|
<label for="customer_email"><?php _e('Email Address', 'wp-digital-download'); ?> *</label>
|
|
<input type="email" id="customer_email" name="customer_email" required />
|
|
</p>
|
|
|
|
<p>
|
|
<label for="customer_name"><?php _e('Full Name', 'wp-digital-download'); ?> *</label>
|
|
<input type="text" id="customer_name" name="customer_name" required />
|
|
</p>
|
|
|
|
<p>
|
|
<label>
|
|
<input type="checkbox" name="create_account" value="1" />
|
|
<?php _e('Create an account for future purchases', 'wp-digital-download'); ?>
|
|
</label>
|
|
</p>
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<?php if (!$is_free) : ?>
|
|
<div class="wpdd-checkout-section">
|
|
<h4><?php _e('Payment Method', 'wp-digital-download'); ?></h4>
|
|
<div id="wpdd-paypal-button"></div>
|
|
</div>
|
|
<?php else : ?>
|
|
<button type="submit" class="wpdd-btn wpdd-btn-primary wpdd-btn-large wpdd-free-download-btn" data-product-id="<?php echo $product_id; ?>">
|
|
<?php _e('Get Free Download', 'wp-digital-download'); ?>
|
|
</button>
|
|
<?php endif; ?>
|
|
</form>
|
|
</div>
|
|
<?php
|
|
return ob_get_clean();
|
|
}
|
|
|
|
public static function thank_you_shortcode($atts) {
|
|
if (!isset($_GET['order_id'])) {
|
|
return '<p>' . __('Invalid order.', 'wp-digital-download') . '</p>';
|
|
}
|
|
|
|
global $wpdb;
|
|
$order_id = sanitize_text_field($_GET['order_id']);
|
|
|
|
// Get order details along with download token
|
|
$order = $wpdb->get_row($wpdb->prepare(
|
|
"SELECT o.*, p.post_title as product_name, dl.token as download_token
|
|
FROM {$wpdb->prefix}wpdd_orders o
|
|
LEFT JOIN {$wpdb->posts} p ON o.product_id = p.ID
|
|
LEFT JOIN {$wpdb->prefix}wpdd_download_links dl ON o.id = dl.order_id
|
|
WHERE o.order_number = %s",
|
|
$order_id
|
|
));
|
|
|
|
if (!$order) {
|
|
return '<p>' . __('Order not found.', 'wp-digital-download') . '</p>';
|
|
}
|
|
|
|
ob_start();
|
|
?>
|
|
<div class="wpdd-thank-you">
|
|
<h2><?php _e('Thank You for Your Purchase!', 'wp-digital-download'); ?></h2>
|
|
|
|
<div class="wpdd-order-details">
|
|
<p><?php _e('Your order has been received and processed successfully.', 'wp-digital-download'); ?></p>
|
|
|
|
<div class="wpdd-order-info">
|
|
<p><strong><?php _e('Order Number:', 'wp-digital-download'); ?></strong> <?php echo esc_html($order->order_number); ?></p>
|
|
<p><strong><?php _e('Product:', 'wp-digital-download'); ?></strong> <?php echo esc_html($order->product_name); ?></p>
|
|
<p><strong><?php _e('Amount:', 'wp-digital-download'); ?></strong> $<?php echo number_format($order->amount, 2); ?></p>
|
|
</div>
|
|
|
|
<div class="wpdd-download-section">
|
|
<h3><?php _e('Download Your Product', 'wp-digital-download'); ?></h3>
|
|
<p><?php _e('A download link has been sent to your email address. You can also download your product using the button below:', 'wp-digital-download'); ?></p>
|
|
|
|
<?php
|
|
// Use token-based download URL which works for unregistered users
|
|
if ($order->download_token) {
|
|
$download_url = add_query_arg(array(
|
|
'wpdd_download_token' => $order->download_token
|
|
), home_url());
|
|
} else {
|
|
// For legacy orders without tokens, create one now
|
|
if (class_exists('WPDD_Download_Handler')) {
|
|
$token = WPDD_Download_Handler::ensure_download_token($order->id);
|
|
if ($token) {
|
|
$download_url = add_query_arg(array(
|
|
'wpdd_download_token' => $token
|
|
), home_url());
|
|
} else {
|
|
// Still fallback to old method if token creation fails
|
|
$download_args = array('wpdd_download' => $order->id);
|
|
|
|
// For guest users, include email and authentication key
|
|
if (!is_user_logged_in()) {
|
|
$download_args['customer_email'] = $order->customer_email;
|
|
$download_args['key'] = substr(md5($order->customer_email . AUTH_KEY), 0, 10);
|
|
}
|
|
|
|
$download_url = wp_nonce_url(
|
|
add_query_arg($download_args),
|
|
'wpdd_download_' . $order->id
|
|
);
|
|
}
|
|
} else {
|
|
// Fallback if WPDD_Download_Handler class not found
|
|
$download_args = array('wpdd_download' => $order->id);
|
|
|
|
// For guest users, include email and authentication key
|
|
if (!is_user_logged_in()) {
|
|
$download_args['customer_email'] = $order->customer_email;
|
|
$download_args['key'] = substr(md5($order->customer_email . AUTH_KEY), 0, 10);
|
|
}
|
|
|
|
$download_url = wp_nonce_url(
|
|
add_query_arg($download_args),
|
|
'wpdd_download_' . $order->id
|
|
);
|
|
}
|
|
}
|
|
?>
|
|
|
|
<a href="<?php echo esc_url($download_url); ?>" class="wpdd-btn wpdd-btn-primary wpdd-btn-large">
|
|
<?php _e('Download Now', 'wp-digital-download'); ?>
|
|
</a>
|
|
</div>
|
|
|
|
<?php if (is_user_logged_in()) : ?>
|
|
<p>
|
|
<?php printf(
|
|
__('You can view all your purchases and re-download files from your <a href="%s">purchase history</a>.', 'wp-digital-download'),
|
|
get_permalink(get_option('wpdd_purchases_page_id'))
|
|
); ?>
|
|
</p>
|
|
<?php endif; ?>
|
|
</div>
|
|
</div>
|
|
<?php
|
|
return ob_get_clean();
|
|
}
|
|
|
|
public static function single_product_shortcode($atts) {
|
|
$atts = shortcode_atts(array(
|
|
'id' => 0
|
|
), $atts);
|
|
|
|
if (!$atts['id']) {
|
|
return '';
|
|
}
|
|
|
|
ob_start();
|
|
self::render_product_card($atts['id']);
|
|
return ob_get_clean();
|
|
}
|
|
|
|
public static function buy_button_shortcode($atts) {
|
|
$atts = shortcode_atts(array(
|
|
'id' => get_the_ID(),
|
|
'text' => __('Buy Now', 'wp-digital-download'),
|
|
'class' => 'wpdd-buy-button'
|
|
), $atts);
|
|
|
|
if (!$atts['id']) {
|
|
return '';
|
|
}
|
|
|
|
return self::render_buy_button($atts['id'], $atts['text'], $atts['class']);
|
|
}
|
|
|
|
public static function render_buy_button($product_id, $text = '', $class = '') {
|
|
global $wpdb;
|
|
|
|
// Check if user already owns this product
|
|
$user_owns_product = false;
|
|
$existing_order = null;
|
|
|
|
if (is_user_logged_in()) {
|
|
$current_user = wp_get_current_user();
|
|
$existing_order = $wpdb->get_row($wpdb->prepare(
|
|
"SELECT * FROM {$wpdb->prefix}wpdd_orders
|
|
WHERE product_id = %d
|
|
AND (customer_id = %d OR customer_email = %s)
|
|
AND status = 'completed'
|
|
ORDER BY purchase_date DESC
|
|
LIMIT 1",
|
|
$product_id,
|
|
$current_user->ID,
|
|
$current_user->user_email
|
|
));
|
|
|
|
if ($existing_order) {
|
|
$user_owns_product = true;
|
|
}
|
|
}
|
|
|
|
// If user already owns the product, show download button
|
|
if ($user_owns_product) {
|
|
$download_url = wp_nonce_url(
|
|
add_query_arg(array('wpdd_download' => $existing_order->id)),
|
|
'wpdd_download_' . $existing_order->id
|
|
);
|
|
|
|
return sprintf(
|
|
'<a href="%s" class="%s wpdd-owned-product">%s</a>',
|
|
esc_url($download_url),
|
|
esc_attr($class ?: 'wpdd-download-button'),
|
|
esc_html(__('Download (Already Purchased)', 'wp-digital-download'))
|
|
);
|
|
}
|
|
|
|
// Regular buy button for products not owned
|
|
$price = get_post_meta($product_id, '_wpdd_price', true);
|
|
$sale_price = get_post_meta($product_id, '_wpdd_sale_price', true);
|
|
$is_free = get_post_meta($product_id, '_wpdd_is_free', true);
|
|
|
|
$actual_price = ($sale_price && $sale_price < $price) ? $sale_price : $price;
|
|
|
|
if (!$text) {
|
|
if ($is_free) {
|
|
$text = __('Download Free', 'wp-digital-download');
|
|
} else {
|
|
$text = sprintf(__('Buy Now - $%s', 'wp-digital-download'), number_format($actual_price, 2));
|
|
}
|
|
}
|
|
|
|
$checkout_url = add_query_arg(array(
|
|
'wpdd_action' => 'add_to_cart',
|
|
'product_id' => $product_id,
|
|
'nonce' => wp_create_nonce('wpdd_add_to_cart')
|
|
), get_permalink(get_option('wpdd_checkout_page_id')));
|
|
|
|
$button_html = sprintf(
|
|
'<a href="%s" class="%s" data-product-id="%d" data-price="%s">%s</a>',
|
|
esc_url($checkout_url),
|
|
esc_attr($class ?: 'wpdd-buy-button'),
|
|
esc_attr($product_id),
|
|
esc_attr($actual_price),
|
|
esc_html($text)
|
|
);
|
|
|
|
return $button_html;
|
|
}
|
|
|
|
public static function add_buy_button_to_product($content) {
|
|
if (!is_singular('wpdd_product')) {
|
|
return $content;
|
|
}
|
|
|
|
global $post;
|
|
|
|
// Get product details
|
|
$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);
|
|
$files = get_post_meta($post->ID, '_wpdd_files', true);
|
|
|
|
// Build product info box
|
|
$product_info = '<div class="wpdd-single-product-info">';
|
|
|
|
// Left section with meta
|
|
$product_info .= '<div class="wpdd-single-meta">';
|
|
|
|
// File count
|
|
if (is_array($files)) {
|
|
$file_count = count($files);
|
|
$product_info .= '<p><strong>' . __('Files:', 'wp-digital-download') . '</strong> ' .
|
|
sprintf(_n('%d file', '%d files', $file_count, 'wp-digital-download'), $file_count) . '</p>';
|
|
}
|
|
|
|
// Creator info with shop filter link
|
|
$creator = get_userdata($post->post_author);
|
|
$shop_page_id = get_option('wpdd_shop_page_id');
|
|
$shop_url = $shop_page_id ? get_permalink($shop_page_id) : home_url('/shop/');
|
|
$creator_filter_url = add_query_arg('wpdd_creator', $creator->ID, $shop_url);
|
|
|
|
$product_info .= '<p><strong>' . __('Created by', 'wp-digital-download') . '</strong> ' .
|
|
'<a href="' . esc_url($creator_filter_url) . '">' . esc_html($creator->display_name) . '</a></p>';
|
|
|
|
// Categories
|
|
$categories = wp_get_post_terms($post->ID, 'wpdd_product_category', array('fields' => 'names'));
|
|
if (!empty($categories)) {
|
|
$product_info .= '<p><strong>' . __('Categories:', 'wp-digital-download') . '</strong> ' .
|
|
implode(', ', $categories) . '</p>';
|
|
}
|
|
|
|
$product_info .= '</div>'; // close meta
|
|
|
|
// Right section with buy button
|
|
$product_info .= '<div class="wpdd-single-purchase">';
|
|
|
|
// Buy button (price is included in button text)
|
|
$product_info .= '<div class="wpdd-single-buy-button">';
|
|
$product_info .= self::render_buy_button($post->ID);
|
|
$product_info .= '</div>';
|
|
|
|
$product_info .= '</div>'; // close purchase section
|
|
$product_info .= '</div>'; // close product info box
|
|
|
|
// Add CSS for the product info box
|
|
$product_info .= '<style>
|
|
.wpdd-single-product-info {
|
|
display: flex;
|
|
flex-direction: row;
|
|
align-items: center;
|
|
justify-content: center;
|
|
width: 100%;
|
|
max-width: 800px;
|
|
background: #f9f9f9;
|
|
border: 1px solid #ddd;
|
|
border-radius: 8px;
|
|
padding: 20px;
|
|
margin: 20px auto;
|
|
box-sizing: border-box;
|
|
gap: 20px;
|
|
}
|
|
.wpdd-single-meta {
|
|
flex: 1;
|
|
padding-right: 20px;
|
|
}
|
|
.wpdd-single-meta p {
|
|
margin: 10px 0;
|
|
font-size: 14px;
|
|
}
|
|
.wpdd-single-meta a {
|
|
color: #0073aa;
|
|
text-decoration: none;
|
|
}
|
|
.wpdd-single-meta a:hover {
|
|
text-decoration: underline;
|
|
}
|
|
.wpdd-single-purchase {
|
|
flex-shrink: 0;
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
justify-content: center;
|
|
min-width: 200px;
|
|
}
|
|
.wpdd-buy-button {
|
|
display: block;
|
|
background: #0073aa;
|
|
color: white !important;
|
|
text-align: center;
|
|
padding: 15px 30px;
|
|
text-decoration: none;
|
|
border-radius: 5px;
|
|
font-size: 18px;
|
|
font-weight: bold;
|
|
transition: background 0.3s;
|
|
white-space: nowrap;
|
|
min-width: 180px;
|
|
}
|
|
.wpdd-buy-button:hover {
|
|
background: #005a87;
|
|
color: white !important;
|
|
}
|
|
.wpdd-owned-product {
|
|
background: #27ae60 !important;
|
|
padding: 15px 40px !important;
|
|
min-width: 250px;
|
|
}
|
|
.wpdd-owned-product:hover {
|
|
background: #229954 !important;
|
|
}
|
|
@media (max-width: 768px) {
|
|
.wpdd-single-product-info {
|
|
flex-direction: column;
|
|
width: 100%;
|
|
max-width: 100%;
|
|
margin: 20px 0;
|
|
}
|
|
.wpdd-single-meta {
|
|
padding-right: 0;
|
|
text-align: center;
|
|
}
|
|
.wpdd-single-purchase {
|
|
min-width: auto;
|
|
width: 100%;
|
|
}
|
|
.wpdd-buy-button {
|
|
width: 100%;
|
|
min-width: auto;
|
|
}
|
|
}
|
|
</style>';
|
|
|
|
// Add the product info box before the content
|
|
return $product_info . $content;
|
|
}
|
|
|
|
public static function creator_dashboard_shortcode($atts) {
|
|
if (!is_user_logged_in()) {
|
|
return '<p>' . __('Please log in to view your creator dashboard.', 'wp-digital-download') . '</p>';
|
|
}
|
|
|
|
$user_id = get_current_user_id();
|
|
|
|
// Check if user is a creator
|
|
if (!WPDD_Creator::is_creator($user_id)) {
|
|
return '<p>' . __('This dashboard is only available for creators.', 'wp-digital-download') . '</p>';
|
|
}
|
|
|
|
global $wpdb;
|
|
|
|
// Get creator stats
|
|
$total_earnings = WPDD_Creator::get_creator_total_earnings($user_id);
|
|
$net_earnings = WPDD_Creator::get_creator_net_earnings($user_id);
|
|
$current_balance = WPDD_Creator::get_creator_balance($user_id);
|
|
$commission_rate = floatval(get_option('wpdd_commission_rate', 0));
|
|
$currency = get_option('wpdd_currency', 'USD');
|
|
$paypal_email = get_user_meta($user_id, 'wpdd_paypal_email', true);
|
|
|
|
// Get recent sales
|
|
$recent_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 20",
|
|
$commission_rate,
|
|
$commission_rate,
|
|
$user_id
|
|
));
|
|
|
|
// 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 10",
|
|
$user_id
|
|
));
|
|
|
|
ob_start();
|
|
?>
|
|
<div class="wpdd-creator-dashboard">
|
|
<h2><?php _e('Creator Dashboard', 'wp-digital-download'); ?></h2>
|
|
|
|
<div class="wpdd-creator-stats">
|
|
<div class="wpdd-stat-box">
|
|
<h3><?php _e('Current Balance', 'wp-digital-download'); ?></h3>
|
|
<div class="wpdd-stat-value"><?php echo wpdd_format_price($current_balance, $currency); ?></div>
|
|
<p class="wpdd-stat-desc"><?php _e('Available for payout', 'wp-digital-download'); ?></p>
|
|
</div>
|
|
|
|
<div class="wpdd-stat-box">
|
|
<h3><?php _e('Total Sales', 'wp-digital-download'); ?></h3>
|
|
<div class="wpdd-stat-value"><?php echo wpdd_format_price($total_earnings, $currency); ?></div>
|
|
<p class="wpdd-stat-desc"><?php _e('Lifetime gross sales', 'wp-digital-download'); ?></p>
|
|
</div>
|
|
|
|
<div class="wpdd-stat-box">
|
|
<h3><?php _e('Net Earnings', 'wp-digital-download'); ?></h3>
|
|
<div class="wpdd-stat-value"><?php echo wpdd_format_price($net_earnings, $currency); ?></div>
|
|
<p class="wpdd-stat-desc"><?php printf(__('After %s%% platform fee', 'wp-digital-download'), $commission_rate); ?></p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="wpdd-creator-settings">
|
|
<h3><?php _e('Payout Settings', 'wp-digital-download'); ?></h3>
|
|
<?php if (empty($paypal_email)) : ?>
|
|
<div class="wpdd-notice wpdd-warning">
|
|
<?php _e('Please add your PayPal email in your profile to receive payouts.', 'wp-digital-download'); ?>
|
|
<a href="<?php echo esc_url(get_edit_profile_url($user_id)); ?>"><?php _e('Edit Profile', 'wp-digital-download'); ?></a>
|
|
</div>
|
|
<?php else : ?>
|
|
<p><?php _e('PayPal Email:', 'wp-digital-download'); ?> <strong><?php echo esc_html($paypal_email); ?></strong>
|
|
<a href="<?php echo esc_url(get_edit_profile_url($user_id)); ?>"><?php _e('Change', 'wp-digital-download'); ?></a></p>
|
|
<?php endif; ?>
|
|
|
|
<?php
|
|
$threshold = floatval(get_option('wpdd_payout_threshold', 0));
|
|
if ($threshold > 0) {
|
|
echo '<p>' . sprintf(__('Automatic payouts are triggered when balance reaches %s', 'wp-digital-download'), wpdd_format_price($threshold, $currency)) . '</p>';
|
|
}
|
|
?>
|
|
</div>
|
|
|
|
<?php if (!empty($recent_sales)) : ?>
|
|
<div class="wpdd-recent-sales">
|
|
<h3><?php _e('Recent Sales', 'wp-digital-download'); ?></h3>
|
|
<table class="wpdd-table">
|
|
<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>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php foreach ($recent_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>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<?php if (!empty($payouts)) : ?>
|
|
<div class="wpdd-payout-history">
|
|
<h3><?php _e('Payout History', 'wp-digital-download'); ?></h3>
|
|
<table class="wpdd-table">
|
|
<thead>
|
|
<tr>
|
|
<th><?php _e('Date', 'wp-digital-download'); ?></th>
|
|
<th><?php _e('Amount', 'wp-digital-download'); ?></th>
|
|
<th><?php _e('Status', 'wp-digital-download'); ?></th>
|
|
<th><?php _e('Transaction ID', 'wp-digital-download'); ?></th>
|
|
<th><?php _e('Method', '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><?php echo wpdd_format_price($payout->amount, $payout->currency); ?></td>
|
|
<td>
|
|
<span class="wpdd-status wpdd-status-<?php echo esc_attr($payout->status); ?>">
|
|
<?php echo esc_html(ucfirst($payout->status)); ?>
|
|
</span>
|
|
</td>
|
|
<td><?php echo esc_html($payout->transaction_id ?: '-'); ?></td>
|
|
<td><?php echo esc_html(ucfirst($payout->payout_method)); ?></td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<style>
|
|
.wpdd-creator-dashboard {
|
|
max-width: 1200px;
|
|
margin: 20px 0;
|
|
}
|
|
.wpdd-creator-stats {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
|
gap: 20px;
|
|
margin-bottom: 30px;
|
|
}
|
|
.wpdd-stat-box {
|
|
background: #f8f9fa;
|
|
border: 1px solid #dee2e6;
|
|
border-radius: 8px;
|
|
padding: 20px;
|
|
text-align: center;
|
|
}
|
|
.wpdd-stat-box h3 {
|
|
margin: 0 0 10px;
|
|
font-size: 14px;
|
|
text-transform: uppercase;
|
|
color: #6c757d;
|
|
}
|
|
.wpdd-stat-value {
|
|
font-size: 32px;
|
|
font-weight: bold;
|
|
color: #212529;
|
|
margin: 10px 0;
|
|
}
|
|
.wpdd-stat-desc {
|
|
color: #6c757d;
|
|
font-size: 12px;
|
|
margin: 5px 0 0;
|
|
}
|
|
.wpdd-creator-settings {
|
|
background: #fff;
|
|
border: 1px solid #dee2e6;
|
|
border-radius: 8px;
|
|
padding: 20px;
|
|
margin-bottom: 30px;
|
|
}
|
|
.wpdd-notice {
|
|
padding: 12px;
|
|
border-radius: 4px;
|
|
margin: 10px 0;
|
|
}
|
|
.wpdd-warning {
|
|
background-color: #fff3cd;
|
|
border: 1px solid #ffc107;
|
|
color: #856404;
|
|
}
|
|
.wpdd-table {
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
margin-top: 15px;
|
|
}
|
|
.wpdd-table th,
|
|
.wpdd-table td {
|
|
padding: 12px;
|
|
text-align: left;
|
|
border-bottom: 1px solid #dee2e6;
|
|
}
|
|
.wpdd-table th {
|
|
background-color: #f8f9fa;
|
|
font-weight: 600;
|
|
}
|
|
.wpdd-status {
|
|
display: inline-block;
|
|
padding: 4px 8px;
|
|
border-radius: 4px;
|
|
font-size: 12px;
|
|
font-weight: 600;
|
|
}
|
|
.wpdd-status-completed {
|
|
background-color: #d4edda;
|
|
color: #155724;
|
|
}
|
|
.wpdd-status-pending {
|
|
background-color: #fff3cd;
|
|
color: #856404;
|
|
}
|
|
.wpdd-status-failed {
|
|
background-color: #f8d7da;
|
|
color: #721c24;
|
|
}
|
|
</style>
|
|
</div>
|
|
<?php
|
|
return ob_get_clean();
|
|
}
|
|
}
|