PluginProbe ʕ •ᴥ•ʔ
GiveWP – Donation Plugin and Fundraising Platform / trunk
GiveWP – Donation Plugin and Fundraising Platform vtrunk
4.16.3 4.16.2 4.16.1 4.16.0 4.15.5 4.15.4 4.15.3 4.15.2 4.15.1 4.15.0 2.3.0 2.3.1 2.3.2 2.30.0 2.31.0 2.31.1 2.32.0 2.33.0 2.33.1 2.33.2 2.33.3 2.33.4 2.33.5 2.4.0 2.4.1 2.4.2 2.4.3 2.4.4 2.4.5 2.4.6 2.4.7 2.5.0 2.5.1 2.5.10 2.5.11 2.5.12 2.5.13 2.5.2 2.5.3 2.5.4 2.5.5 2.5.6 2.5.7 2.5.8 2.5.9 2.6.0 2.6.1 2.6.2 2.6.3 2.7.0 2.7.1 2.7.2 2.7.3 2.7.4 2.7.5 2.8.0 2.8.1 2.9.0 2.9.1 2.9.2 2.9.3 2.9.4 2.9.5 2.9.6 2.9.7 3.0.0 3.0.1 3.0.2 3.0.3 3.0.4 3.1.0 3.1.1 3.1.2 3.10.0 3.11.0 3.12.0 3.12.1 3.12.2 3.12.3 3.13.0 3.14.0 3.14.1 3.14.2 3.15.0 3.15.1 3.16.0 3.16.1 3.16.2 3.16.3 3.16.4 3.16.5 3.17.0 3.17.1 3.17.2 3.18.0 3.19.0 3.19.1 3.19.2 3.19.3 3.19.4 3.2.0 3.2.1 3.2.2 3.20.0 3.21.0 3.21.1 3.22.0 3.22.1 3.22.2 3.3.0 3.3.1 3.4.0 3.4.1 3.4.2 3.5.0 3.5.1 3.6.0 3.6.1 3.6.2 3.7.0 3.8.0 3.9.0 4.0.0 4.1.0 4.1.1 4.10.0 4.10.1 4.11.0 4.12.0 4.13.0 4.13.1 4.13.2 4.14.0 4.14.1 4.14.2 4.14.3 4.14.4 4.14.5 4.14.6 4.2.0 4.2.1 4.3.0 4.3.1 4.3.2 4.4.0 4.5.0 4.6.1 4.7.0 4.7.1 4.8.0 4.8.1 4.9.0 trunk 1.9.0 2.0.0 2.0.1 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.1.0 2.1.1 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.1.7 2.1.8 2.10.0 2.10.1 2.10.2 2.10.3 2.10.4 2.11.0 2.11.1 2.11.2 2.11.3 2.12.0 2.12.1 2.12.2 2.12.3 2.13.0 2.13.1 2.13.2 2.13.3 2.13.4 2.14.0 2.15.0 2.16.0 2.16.1 2.17.0 2.17.1 2.17.3 2.18.0 2.18.1 2.19.1 2.19.2 2.19.3 2.19.4 2.19.5 2.19.6 2.19.7 2.19.8 2.2.0 2.2.1 2.2.2 2.2.3 2.2.4 2.2.5 2.2.6 2.20.0 2.20.1 2.20.2 2.21.0 2.21.1 2.21.2 2.21.3 2.21.4 2.22.0 2.22.1 2.22.2 2.22.3 2.23.0 2.23.1 2.23.2 2.24.0 2.24.1 2.24.2 2.25.0 2.25.1 2.25.2 2.25.3 2.26.0 2.27.0 2.27.1 2.27.2 2.27.3 2.28.0 2.29.0 2.29.1 2.29.2
give / src / Donations / Endpoints / ListDonations.php
give / src / Donations / Endpoints Last commit date
DonationActions.php 5 months ago Endpoint.php 5 months ago ListDonations.php 8 months ago ListDonationsStats.php 9 months ago SwitchDonationView.php 4 years ago
ListDonations.php
340 lines
1 <?php
2
3 namespace Give\Donations\Endpoints;
4
5 use Give\Donations\ListTable\DonationsListTable;
6 use Give\Donations\ValueObjects\DonationMetaKeys;
7 use Give\Donations\ValueObjects\DonationMode;
8 use Give\Donations\ValueObjects\DonationStatus;
9 use Give\Framework\Database\DB;
10 use Give\Framework\ListTable\Exceptions\ColumnIdCollisionException;
11 use Give\Framework\QueryBuilder\QueryBuilder;
12 use WP_REST_Request;
13 use WP_REST_Response;
14
15 /**
16 * @since 4.0.0 replace form with campaignId.
17 * @since 3.4.0 The class is extendable
18 */
19 class ListDonations extends Endpoint
20 {
21 /**
22 * @var string
23 */
24 protected $endpoint = 'admin/donations';
25
26 /**
27 * @var WP_REST_Request
28 */
29 protected $request;
30
31 /**
32 * @var DonationsListTable
33 */
34 protected $listTable;
35
36 /**
37 * @since 4.12.0 Updated status parameter to accept multiple comma-separated values
38 * @since 4.6.0 add status parameter to filter donations by status
39 * @since 3.4.0
40 * @access public
41 */
42 public function __construct(DonationsListTable $listTable)
43 {
44 $this->listTable = $listTable;
45 }
46
47 /**
48 * @inheritDoc
49 *
50 * @since 4.12.0 Add format parameter to start and end dates, replacing custom validation callback
51 * @since 3.4.0
52 */
53 public function registerRoute()
54 {
55 register_rest_route(
56 'give-api/v2',
57 $this->endpoint,
58 [
59 [
60 'methods' => 'GET',
61 'callback' => [$this, 'handleRequest'],
62 'permission_callback' => [$this, 'permissionsCheck'],
63 ],
64 'args' => [
65 'page' => [
66 'type' => 'integer',
67 'required' => false,
68 'default' => 1,
69 'minimum' => 1
70 ],
71 'perPage' => [
72 'type' => 'integer',
73 'required' => false,
74 'default' => 30,
75 'minimum' => 1
76 ],
77 'campaignId' => [
78 'type' => 'integer',
79 'required' => false,
80 'default' => 0
81 ],
82 'search' => [
83 'type' => 'string',
84 'required' => false,
85 'sanitize_callback' => 'sanitize_text_field',
86 ],
87 'start' => [
88 'type' => 'string',
89 'required' => false,
90 'format' => 'date-time'
91 ],
92 'end' => [
93 'type' => 'string',
94 'required' => false,
95 'format' => 'date-time'
96 ],
97 'donor' => [
98 'type' => 'string',
99 'required' => false,
100 'sanitize_callback' => 'sanitize_text_field',
101 ],
102 'sortColumn' => [
103 'type' => 'string',
104 'required' => false,
105 'sanitize_callback' => 'sanitize_text_field',
106 ],
107 'sortDirection' => [
108 'type' => 'string',
109 'required' => false,
110 'enum' => [
111 'asc',
112 'desc',
113 ],
114 ],
115 'locale' => [
116 'type' => 'string',
117 'required' => false,
118 'default' => get_locale(),
119 ],
120 'testMode' => [
121 'type' => 'boolean',
122 'required' => false,
123 'default' => give_is_test_mode(),
124 ],
125 'return' => [
126 'type' => 'string',
127 'required' => false,
128 'default' => 'columns',
129 'enum' => [
130 'model',
131 'columns',
132 ],
133 ],
134 'status' => [
135 'type' => 'array',
136 'required' => false,
137 'items' => [
138 'type' => 'string',
139 'enum' => array_values(DonationStatus::toArray()),
140 ],
141 'description' => 'Filter donations by status. Accepts comma-separated list of DonationStatus values (e.g., "pending,publish,trash"). If not provided, excludes trash donations by default.'
142 ],
143 ],
144 ]
145 );
146 }
147
148 /**
149 * @since 2.24.0 Change this to use the new ListTable class
150 * @since 2.20.0
151 *
152 * @param WP_REST_Request $request
153 *
154 * @return WP_REST_Response
155 * @throws ColumnIdCollisionException
156 */
157 public function handleRequest(WP_REST_Request $request): WP_REST_Response
158 {
159 $this->request = $request;
160
161 $donations = $this->getDonations();
162 $donationsCount = $this->getTotalDonationsCount();
163 $totalPages = (int)ceil($donationsCount / $this->request->get_param('perPage'));
164
165 if ('model' === $this->request->get_param('return')) {
166 $items = $donations;
167 } else {
168 $this->listTable->items($donations, $this->request->get_param('locale') ?? '');
169 $items = $this->listTable->getItems();
170 }
171
172 return new WP_REST_Response(
173 [
174 'items' => $items,
175 'totalItems' => $donationsCount,
176 'totalPages' => $totalPages,
177 ]
178 );
179 }
180
181 /**
182 * @since 2.24.0 Replace Query Builder with Donations model
183 * @since 2.21.0
184 *
185 * @return array
186 */
187 public function getDonations(): array
188 {
189 $page = $this->request->get_param('page');
190 $perPage = $this->request->get_param('perPage');
191 $sortColumns = $this->listTable->getSortColumnById($this->request->get_param('sortColumn') ?: 'id');
192 $sortDirection = $this->request->get_param('sortDirection') ?: 'desc';
193
194 $query = give()->donations->prepareQuery();
195 list($query) = $this->getWhereConditions($query);
196
197 foreach ($sortColumns as $sortColumn) {
198 $query->orderBy($sortColumn, $sortDirection);
199 }
200
201 $query->limit($perPage)
202 ->offset(($page - 1) * $perPage);
203
204 $donations = $query->getAll();
205
206 if (!$donations) {
207 return [];
208 }
209
210 return $donations;
211 }
212
213 /**
214 * @since 2.24.0 Replace Query Builder with Donations model
215 * @since 2.21.0
216 *
217 * @return int
218 */
219 public function getTotalDonationsCount(): int
220 {
221 $query = DB::table('posts')
222 ->where('post_type', 'give_payment')
223 ->groupBy('mode');
224
225 list($query, $dependencies) = $this->getWhereConditions($query);
226
227 $query->attachMeta(
228 'give_donationmeta',
229 'ID',
230 'donation_id',
231 ...DonationMetaKeys::getColumnsForAttachMetaQueryFromArray($dependencies)
232 );
233
234 return $query->count();
235 }
236
237 /**
238 * @since 4.12.0 Updated status filtering to accept multiple comma-separated values
239 * @since 4.8.0 Added support for subscriptionId parameter to filter donations
240 * @since 4.6.0 add status status condition to filter donations
241 * @since 3.4.0 Make this method protected so it can be extended
242 * @since 3.2.0 Updated query to account for possible null and empty values for _give_payment_mode meta
243 * @since 2.24.0 Remove joins as it uses ModelQueryBuilder and change clauses to use attach_meta
244 * @since 2.21.0
245 *
246 * @param QueryBuilder $query
247 *
248 * @return array{0: QueryBuilder, 1: array<DonationMetaKeys>}
249 */
250 protected function getWhereConditions(QueryBuilder $query): array
251 {
252 $search = $this->request->get_param('search');
253 $start = $this->request->get_param('start');
254 $end = $this->request->get_param('end');
255 $donor = $this->request->get_param('donor');
256 $testMode = $this->request->get_param('testMode');
257 $campaignId = $this->request->get_param('campaignId');
258 $subscriptionId = $this->request->get_param('subscriptionId');
259 $status = $this->request->get_param('status');
260 $dependencies = [
261 DonationMetaKeys::MODE(),
262 ];
263
264 $hasWhereConditions = $search || $start || $end || $campaignId || $subscriptionId || $donor || $status;
265
266 $query->where('post_type', 'give_payment');
267
268 if (!empty($status)) {
269 $query->whereIn('post_status', $status);
270 } else {
271 // Default behavior: exclude trash donations
272 $query->where('post_status', DonationStatus::TRASH, '<>');
273 }
274
275 if ($search) {
276 if (ctype_digit($search)) {
277 $query->where('id', $search);
278 } elseif (strpos($search, '@') !== false) {
279 $query
280 ->whereLike('give_donationmeta_attach_meta_email.meta_value', $search);
281 $dependencies[] = DonationMetaKeys::EMAIL();
282 } else {
283 $query
284 ->whereLike('give_donationmeta_attach_meta_firstName.meta_value', $search)
285 ->orWhereLike('give_donationmeta_attach_meta_lastName.meta_value', $search);
286 $dependencies[] = DonationMetaKeys::FIRST_NAME();
287 $dependencies[] = DonationMetaKeys::LAST_NAME();
288 }
289 }
290
291 if ($donor) {
292 if (ctype_digit($donor)) {
293 $query
294 ->where('give_donationmeta_attach_meta_donorId.meta_value', $donor);
295 $dependencies[] = DonationMetaKeys::DONOR_ID();
296 } else {
297 $query
298 ->whereLike('give_donationmeta_attach_meta_firstName.meta_value', $donor)
299 ->orWhereLike('give_donationmeta_attach_meta_lastName.meta_value', $donor);
300 $dependencies[] = DonationMetaKeys::FIRST_NAME();
301 $dependencies[] = DonationMetaKeys::LAST_NAME();
302 }
303 }
304
305 if ($campaignId) {
306 $query
307 ->where('give_donationmeta_attach_meta_campaignId.meta_value', $campaignId);
308 $dependencies[] = DonationMetaKeys::CAMPAIGN_ID();
309 }
310
311 if ($subscriptionId) {
312 $query
313 ->where('give_donationmeta_attach_meta_subscriptionId.meta_value', $subscriptionId);
314 $dependencies[] = DonationMetaKeys::SUBSCRIPTION_ID();
315 }
316
317 if ($start && $end) {
318 $query->whereBetween('post_date', $start, $end);
319 } elseif ($start) {
320 $query->where('post_date', $start, '>=');
321 } elseif ($end) {
322 $query->where('post_date', $end, '<=');
323 }
324
325 if ($hasWhereConditions) {
326 $query->havingRaw('HAVING COALESCE(give_donationmeta_attach_meta_mode.meta_value, %s) = %s', DonationMode::LIVE, $testMode ? DonationMode::TEST : DonationMode::LIVE);
327 } elseif ($testMode) {
328 $query->where('give_donationmeta_attach_meta_mode.meta_value', DonationMode::TEST);
329 } else {
330 $query->whereIsNull('give_donationmeta_attach_meta_mode.meta_value')
331 ->orWhere('give_donationmeta_attach_meta_mode.meta_value', DonationMode::TEST, '<>');
332 }
333
334 return [
335 $query,
336 $dependencies,
337 ];
338 }
339 }
340