roles); $is_admin = current_user_can('manage_options'); if ($is_admin) { // Full admin menus add_submenu_page( 'edit.php?post_type=wpdd_product', __('Orders', 'wp-digital-download'), __('Orders', 'wp-digital-download'), 'wpdd_manage_orders', 'wpdd-orders', array(__CLASS__, 'render_orders_page') ); add_submenu_page( 'edit.php?post_type=wpdd_product', __('Reports', 'wp-digital-download'), __('Reports', 'wp-digital-download'), 'wpdd_view_reports', 'wpdd-reports', array(__CLASS__, 'render_reports_page') ); add_submenu_page( 'edit.php?post_type=wpdd_product', __('Customers', 'wp-digital-download'), __('Customers', 'wp-digital-download'), 'wpdd_manage_orders', 'wpdd-customers', array(__CLASS__, 'render_customers_page') ); add_submenu_page( 'edit.php?post_type=wpdd_product', __('Shortcodes', 'wp-digital-download'), __('Shortcodes', 'wp-digital-download'), 'edit_wpdd_products', 'wpdd-shortcodes', array(__CLASS__, 'render_shortcodes_page') ); } if ($is_creator || $is_admin) { // Creator-specific menus add_submenu_page( 'edit.php?post_type=wpdd_product', __('My Sales', 'wp-digital-download'), __('My Sales', 'wp-digital-download'), 'wpdd_view_own_sales', 'wpdd-creator-sales', array(__CLASS__, 'render_creator_sales_page') ); add_submenu_page( 'edit.php?post_type=wpdd_product', __('My Payouts', 'wp-digital-download'), __('My Payouts', 'wp-digital-download'), 'wpdd_view_own_sales', 'wpdd-creator-payouts', array(__CLASS__, 'render_creator_payouts_page') ); } } public static function add_product_columns($columns) { $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 '' . __('Free', 'wp-digital-download') . ''; } elseif ($sale_price && $sale_price < $price) { echo '$' . number_format($price, 2) . ' '; echo '$' . number_format($sale_price, 2) . ''; } 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; $product_type = get_post_meta($post_id, '_wpdd_product_type', true); echo $count; // Add sync button for software license products with no files if ($product_type === 'software_license' && $count === 0) { $nonce = wp_create_nonce('wpdd_sync_product_' . $post_id); echo '
'; } 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 )); ?>

#order_number); ?> product_name); ?> customer_name); ?>
customer_email); ?>
$amount, 2); ?> status); ?> purchase_date)); ?>
1) { echo '
'; echo paginate_links(array( 'base' => add_query_arg('paged', '%#%'), 'format' => '', 'current' => $page, 'total' => $total_pages )); echo '
'; } ?>
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 )); ?>

$total_revenue ?: 0, 2); ?>

total_orders); ?>

unique_customers); ?>

products_sold); ?>

post_title); ?> sales); ?> $revenue, 2); ?>

display_name); ?> sales); ?> $revenue, 2); ?>
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" ); ?>

display_name); ?> user_email); ?> total_orders); ?> $total_spent ?: 0, 2); ?> user_registered)); ?> last_order_date ? date_i18n(get_option('date_format'), strtotime($customer->last_order_date)) : '-'; ?>
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() { ?>

[wpdd_shop]

  • posts_per_page - Number of products per page (default: 12)
  • columns - Grid columns (default: 3, options: 1-6)
  • orderby - Sort order (date, title, price, menu_order)
  • order - ASC or DESC (default: DESC)
  • category - Show only specific categories (comma separated slugs)
  • show_filters - Show search/filter form (yes/no, default: yes)

[wpdd_shop posts_per_page="6" columns="2"]
[wpdd_shop category="music,videos" show_filters="no"]
[wpdd_shop orderby="price" order="ASC" columns="4"]

[wpdd_checkout]

[wpdd_customer_purchases]

[wpdd_thank_you]

[wpdd_single_product id="123"]

  • id - Product ID (required)

[wpdd_single_product id="456"]

[wpdd_buy_button id="123"]

  • id - Product ID (default: current post ID)
  • text - Button text (default: "Buy Now")
  • class - CSS class for styling

[wpdd_buy_button id="789" text="Purchase Now"]
[wpdd_buy_button text="Get This Product" class="my-custom-button"]

[wpdd_shop] ✓ ' . __('Created', 'wp-digital-download') . ''; echo ' (' . __('Edit', 'wp-digital-download') . ')'; } else { echo '✗ ' . __('Missing', 'wp-digital-download') . ''; } ?>
[wpdd_checkout] ✓ ' . __('Created', 'wp-digital-download') . ''; echo ' (' . __('Edit', 'wp-digital-download') . ')'; } else { echo '✗ ' . __('Missing', 'wp-digital-download') . ''; } ?>
[wpdd_customer_purchases] ✓ ' . __('Created', 'wp-digital-download') . ''; echo ' (' . __('Edit', 'wp-digital-download') . ')'; } else { echo '✗ ' . __('Missing', 'wp-digital-download') . ''; } ?>
[wpdd_thank_you] ✓ ' . __('Created', 'wp-digital-download') . ''; echo ' (' . __('Edit', 'wp-digital-download') . ')'; } else { echo '✗ ' . __('Missing', 'wp-digital-download') . ''; } ?>
is_main_query()) { return; } if (!isset($_GET['post_type']) || $_GET['post_type'] !== 'wpdd_product') { return; } $user = wp_get_current_user(); $is_creator = in_array('wpdd_creator', (array) $user->roles); $is_admin = current_user_can('manage_options'); // Only filter for creators, not admins if ($is_creator && !$is_admin) { $query->set('author', get_current_user_id()); } } public static function render_creator_sales_page() { global $wpdb; $user_id = get_current_user_id(); $currency = get_option('wpdd_currency', 'USD'); $commission_rate = floatval(get_option('wpdd_commission_rate', 0)); // Get creator's sales data $sales = $wpdb->get_results($wpdb->prepare( "SELECT o.*, p.post_title as product_name, (o.total * %f / 100) as platform_fee, (o.total * (100 - %f) / 100) as creator_earning FROM {$wpdb->prefix}wpdd_orders o INNER JOIN {$wpdb->posts} p ON o.product_id = p.ID WHERE p.post_author = %d AND o.status = 'completed' ORDER BY o.purchase_date DESC LIMIT 100", $commission_rate, $commission_rate, $user_id )); // Get totals $total_sales = $wpdb->get_var($wpdb->prepare( "SELECT SUM(o.total) FROM {$wpdb->prefix}wpdd_orders o INNER JOIN {$wpdb->posts} p ON o.product_id = p.ID WHERE p.post_author = %d AND o.status = 'completed'", $user_id )); $total_earnings = $total_sales * (1 - ($commission_rate / 100)); $current_balance = WPDD_Creator::get_creator_balance($user_id); ?>

purchase_date))); ?> product_name); ?> customer_name); ?> total, $currency); ?> platform_fee, $currency); ?> creator_earning, $currency); ?> status)); ?>

get_results($wpdb->prepare( "SELECT * FROM {$wpdb->prefix}wpdd_payouts WHERE creator_id = %d ORDER BY created_at DESC LIMIT 50", $user_id )); ?>

0) : ?>

created_at))); ?> amount, $payout->currency); ?> paypal_email); ?> '#fef3c7; color: #92400e;', 'completed' => '#d1fae5; color: #065f46;', 'failed' => '#fee2e2; color: #991b1b;', 'requested' => '#dbeafe; color: #1e40af;' ); $status_color = isset($status_colors[$payout->status]) ? $status_colors[$payout->status] : '#f3f4f6; color: #374151;'; ?> status)); ?> transaction_id ?: '-'); ?> processed_at ? esc_html(date_i18n(get_option('date_format'), strtotime($payout->processed_at))) : '-'; ?>

insert( $wpdb->prefix . 'wpdd_payouts', array( 'creator_id' => $user_id, 'amount' => $balance, 'currency' => $currency, 'paypal_email' => $paypal_email, 'status' => 'requested', 'payout_method' => 'request', 'created_at' => current_time('mysql') ), array('%d', '%f', '%s', '%s', '%s', '%s', '%s') ); // Reset balance to 0 since it's now requested update_user_meta($user_id, 'wpdd_creator_balance', 0); // Redirect to avoid resubmission wp_redirect(admin_url('edit.php?post_type=wpdd_product&page=wpdd-creator-payouts&message=payout_requested')); exit; } public static function handle_sync_software_product() { if (!current_user_can('edit_wpdd_products')) { wp_die('Unauthorized'); } if (!isset($_POST['product_id']) || !wp_verify_nonce($_POST['nonce'], 'wpdd_sync_product_' . $_POST['product_id'])) { wp_die('Invalid nonce'); } $product_id = intval($_POST['product_id']); if (!class_exists('WPDD_API')) { require_once WPDD_PLUGIN_PATH . 'includes/class-wpdd-api.php'; } $result = WPDD_API::sync_software_product($product_id, true); wp_send_json($result); } public static function handle_regenerate_licenses() { if (!current_user_can('manage_options')) { wp_die('Unauthorized'); } if (!wp_verify_nonce($_POST['nonce'], 'wpdd_regenerate_licenses')) { wp_die('Invalid nonce'); } global $wpdb; // Find completed orders for software license products that don't have license keys $orders = $wpdb->get_results(" SELECT o.*, pm.meta_value as product_type FROM {$wpdb->prefix}wpdd_orders o LEFT JOIN {$wpdb->postmeta} pm ON o.product_id = pm.post_id AND pm.meta_key = '_wpdd_product_type' LEFT JOIN {$wpdb->prefix}wpdd_licenses l ON o.id = l.order_id WHERE o.status = 'completed' AND pm.meta_value = 'software_license' AND l.license_key IS NULL "); $generated = 0; foreach ($orders as $order) { if (class_exists('WPDD_License_Manager')) { $license_key = WPDD_License_Manager::create_license($order->id); if ($license_key) { $generated++; } } } wp_send_json(array( 'success' => true, 'message' => sprintf('Generated %d license keys for existing orders.', $generated), 'generated' => $generated )); } }