PluginProbe
Better Payment – Instant Payments, Donations, Fundraising with Subscriptions & More / 2.4.1
Better Payment – Instant Payments, Donations, Fundraising with Subscriptions & More v2.4.1
2.4.1 2.4.0 2.3.4 2.3.3 2.3.2 2.3.1 2.3.0 2.2.2 2.2.1 2.2.0 2.1.2 2.1.1 trunk 0.0.1 0.0.2 0.0.3 0.0.4 0.0.5 0.0.6 0.0.7 1.0.0 1.0.1 1.0.2 1.0.3 1.0.4 All 68 releases
← All changes | includes/Campaign/CampaignStats.php +25 -9 2.2.2 → 2.4.1 View file →
@@ -1,8 +1,9 @@
1 1 <?php
2 2
3 3 namespace Better_Payment\Lite\Campaign;
4 4
5 +use Better_Payment\Lite\Classes\Helper;
5 6 use Better_Payment\Lite\Controller;
6 7
7 8 if ( ! defined( 'ABSPATH' ) ) {
8 9 exit;
@@ -9,8 +10,25 @@
9 10 }
10 11
11 12 /**
12 13 * Computes and caches campaign stats (total raised, donor count, progress %).
14 + *
15 + * `donor_count` is the count of approved donation *transactions*, not of unique
16 + * donors — it must agree with the per-transaction list the Donors Wall renders
17 + * (one card per approved row). Counting distinct emails made the summary read
18 + * "3 Donors" above a 5-card list; a repeat donor (or a row with an empty email,
19 + * which `COUNT(DISTINCT email)` drops entirely) is one transaction here.
20 + *
21 + * Which rows count, and what they add, is Helper::approved_donation_sql() and
22 + * Helper::COUNTABLE_AMOUNT_SQL — the one definition every aggregation shares.
23 + *
24 + * A confirmed donation that charged nothing — a 100%-off promotion code, a subscription trial —
25 + * is a donor too: Handler::confirm_stripe_session() stores it `paid` with its real amount, 0, so
26 + * it adds one to `donor_count` and nothing to `total_raised`. Nothing here filters on the amount.
27 + * Rows confirmed before 2.4.0 stored such a session as `no_payment_required` at the form's
28 + * amount: one that was confirmed counts as a donor and adds 0 (its stored amount was never
29 + * charged); one that never was (Stripe reports the same status for a free checkout at creation)
30 + * is not counted at all. See Helper::LEGACY_CONFIRMATION_MARKER.
13 31 */
14 32 class CampaignStats extends Controller {
15 33
16 34 private static int $cache_ttl = 2 * MINUTE_IN_SECONDS;
@@ -91,20 +109,22 @@
91 109
92 110 private static function query_stats( int $campaign_id ): array {
93 111 global $wpdb;
94 112
95 - $payment_table = $wpdb->prefix . 'better_payment';
96 - $approved_statuses = "'" . implode( "','", array_map( 'esc_sql', self::approved_statuses() ) ) . "'";
113 + $payment_table = $wpdb->prefix . 'better_payment';
114 + $approved = Helper::approved_donation_sql();
115 + $amount = Helper::COUNTABLE_AMOUNT_SQL;
97 116
117 + // Both fragments are Helper constants (no request data, no `%`).
98 118 $row = $wpdb->get_row(
99 119 $wpdb->prepare(
100 120 "SELECT
101 - COALESCE(SUM(amount), 0) AS total_raised,
102 - COUNT(DISTINCT email) AS donor_count,
121 + COALESCE(SUM({$amount}), 0) AS total_raised,
122 + COUNT(*) AS donor_count,
103 123 MAX(payment_date) AS last_donation_date
104 124 FROM `{$payment_table}`
105 125 WHERE campaign_id = %s
106 - AND status IN ({$approved_statuses})",
126 + AND {$approved}",
107 127 (string) $campaign_id
108 128 ),
109 129 ARRAY_A
110 130 );
@@ -113,10 +133,6 @@
113 133 'total_raised' => (float) ( $row['total_raised'] ?? 0 ),
114 134 'donor_count' => (int) ( $row['donor_count'] ?? 0 ),
115 135 'last_donation_date' => $row['last_donation_date'] ?? null,
116 136 ];
117 - }
118 -
119 - private static function approved_statuses(): array {
120 - return [ 'Completed', 'paid', 'complete', 'succeeded' ];
121 137 }
122 138 }