|
1
|
|
|
<?php |
|
|
|
|
|
|
2
|
|
|
/** |
|
3
|
|
|
* Batch Donors Export Class |
|
4
|
|
|
* |
|
5
|
|
|
* This class handles donor export. |
|
6
|
|
|
* |
|
7
|
|
|
* @package Give |
|
8
|
|
|
* @subpackage Admin/Reports |
|
9
|
|
|
* @copyright Copyright (c) 2016, WordImpress |
|
10
|
|
|
* @license https://opensource.org/licenses/gpl-license GNU Public License |
|
11
|
|
|
* @since 1.5 |
|
12
|
|
|
*/ |
|
13
|
|
|
|
|
14
|
|
|
// Exit if accessed directly. |
|
15
|
|
|
if ( ! defined( 'ABSPATH' ) ) { |
|
16
|
|
|
exit; |
|
17
|
|
|
} |
|
18
|
|
|
|
|
19
|
|
|
/** |
|
20
|
|
|
* Give_Batch_Donors_Export Class |
|
21
|
|
|
* |
|
22
|
|
|
* @since 1.5 |
|
23
|
|
|
*/ |
|
24
|
|
|
class Give_Batch_Donors_Export extends Give_Batch_Export { |
|
25
|
|
|
|
|
26
|
|
|
/** |
|
27
|
|
|
* Our export type. Used for export-type specific filters/actions. |
|
28
|
|
|
* |
|
29
|
|
|
* @var string |
|
30
|
|
|
* @since 1.5 |
|
31
|
|
|
*/ |
|
32
|
|
|
public $export_type = 'donors'; |
|
33
|
|
|
|
|
34
|
|
|
/** |
|
35
|
|
|
* Form submission data |
|
36
|
|
|
* |
|
37
|
|
|
* @var array |
|
38
|
|
|
* @since 1.5 |
|
39
|
|
|
*/ |
|
40
|
|
|
private $data = array(); |
|
41
|
|
|
|
|
42
|
|
|
/** |
|
43
|
|
|
* Array of donor ids which is already included in csv file. |
|
44
|
|
|
* |
|
45
|
|
|
* @since 1.8 |
|
46
|
|
|
* @var array |
|
47
|
|
|
*/ |
|
48
|
|
|
private $donor_ids = array(); |
|
49
|
|
|
|
|
50
|
|
|
/** |
|
51
|
|
|
* Array of payment stats which is already included in csv file. |
|
52
|
|
|
* |
|
53
|
|
|
* @since 1.8.9 |
|
54
|
|
|
* @var array |
|
55
|
|
|
*/ |
|
56
|
|
|
private $payment_stats = array(); |
|
57
|
|
|
|
|
58
|
|
|
/** |
|
59
|
|
|
* Export query id. |
|
60
|
|
|
* |
|
61
|
|
|
* @since 1.8 |
|
62
|
|
|
* @var string |
|
63
|
|
|
*/ |
|
64
|
|
|
private $query_id = ''; |
|
65
|
|
|
|
|
66
|
|
|
/** |
|
67
|
|
|
* Set the properties specific to the donors export. |
|
68
|
|
|
* |
|
69
|
|
|
* @since 1.5 |
|
70
|
|
|
* |
|
71
|
|
|
* @param array $request The Form Data passed into the batch processing |
|
72
|
|
|
*/ |
|
73
|
|
|
public function set_properties( $request ) { |
|
74
|
|
|
|
|
75
|
|
|
// Set data from form submission |
|
76
|
|
|
if ( isset( $_POST['form'] ) ) { |
|
77
|
|
|
parse_str( $_POST['form'], $this->data ); |
|
78
|
|
|
} |
|
79
|
|
|
|
|
80
|
|
|
$this->form = $this->data['forms']; |
|
81
|
|
|
|
|
82
|
|
|
// Setup donor ids cache. |
|
83
|
|
|
if ( ! empty( $this->form ) ) { |
|
84
|
|
|
// Cache donor ids to output unique list of donor. |
|
85
|
|
|
$this->query_id = give_clean( $_REQUEST['give_export_option']['query_id'] ); |
|
86
|
|
|
$this->cache_donor_ids(); |
|
87
|
|
|
} |
|
88
|
|
|
|
|
89
|
|
|
$this->price_id = ! empty( $request['give_price_option'] ) && 'all' !== $request['give_price_option'] ? absint( $request['give_price_option'] ) : null; |
|
90
|
|
|
|
|
91
|
|
|
} |
|
92
|
|
|
|
|
93
|
|
|
|
|
94
|
|
|
/** |
|
95
|
|
|
* Cache donor ids. |
|
96
|
|
|
* |
|
97
|
|
|
* @since 1.8.9 |
|
98
|
|
|
* @access private |
|
99
|
|
|
*/ |
|
100
|
|
|
private function cache_donor_ids() { |
|
101
|
|
|
// Fetch already cached donor ids. |
|
102
|
|
|
$donor_ids = $this->donor_ids; |
|
103
|
|
|
|
|
104
|
|
|
if ( $cached_donor_ids = Give_Cache::get( $this->query_id, true ) ) { |
|
105
|
|
|
$donor_ids = array_unique( array_merge( $cached_donor_ids, $this->donor_ids ) ); |
|
106
|
|
|
} |
|
107
|
|
|
|
|
108
|
|
|
$donor_ids = array_values( $donor_ids ); |
|
109
|
|
|
Give_Cache::set( $this->query_id, $donor_ids, HOUR_IN_SECONDS, true ); |
|
110
|
|
|
} |
|
111
|
|
|
|
|
112
|
|
|
/** |
|
113
|
|
|
* Set the CSV columns. |
|
114
|
|
|
* |
|
115
|
|
|
* @access public |
|
116
|
|
|
* @since 1.5 |
|
117
|
|
|
* @return array|bool $cols All the columns. |
|
118
|
|
|
*/ |
|
119
|
|
|
public function csv_cols() { |
|
120
|
|
|
|
|
121
|
|
|
$columns = isset( $this->data['give_export_option'] ) ? $this->data['give_export_option'] : array(); |
|
122
|
|
|
|
|
123
|
|
|
// We need columns. |
|
124
|
|
|
if ( empty( $columns ) ) { |
|
125
|
|
|
return false; |
|
126
|
|
|
} |
|
127
|
|
|
|
|
128
|
|
|
$cols = $this->get_cols( $columns ); |
|
129
|
|
|
|
|
130
|
|
|
return $cols; |
|
131
|
|
|
} |
|
132
|
|
|
|
|
133
|
|
|
/** |
|
134
|
|
|
* CSV file columns. |
|
135
|
|
|
* |
|
136
|
|
|
* @param array $columns |
|
137
|
|
|
* |
|
138
|
|
|
* @return array |
|
139
|
|
|
*/ |
|
140
|
|
|
private function get_cols( $columns ) { |
|
141
|
|
|
|
|
142
|
|
|
$cols = array(); |
|
143
|
|
|
|
|
144
|
|
|
foreach ( $columns as $key => $value ) { |
|
145
|
|
|
|
|
146
|
|
|
switch ( $key ) { |
|
147
|
|
|
case 'full_name' : |
|
148
|
|
|
$cols['full_name'] = esc_html__( 'Full Name', 'give' ); |
|
149
|
|
|
break; |
|
150
|
|
|
case 'email' : |
|
151
|
|
|
$cols['email'] = esc_html__( 'Email Address', 'give' ); |
|
152
|
|
|
break; |
|
153
|
|
|
case 'address' : |
|
154
|
|
|
$cols['address_line1'] = esc_html__( 'Address', 'give' ); |
|
155
|
|
|
$cols['address_line2'] = esc_html__( 'Address 2', 'give' ); |
|
156
|
|
|
$cols['address_city'] = esc_html__( 'City', 'give' ); |
|
157
|
|
|
$cols['address_state'] = esc_html__( 'State', 'give' ); |
|
158
|
|
|
$cols['address_zip'] = esc_html__( 'Zip', 'give' ); |
|
159
|
|
|
$cols['address_country'] = esc_html__( 'Country', 'give' ); |
|
160
|
|
|
break; |
|
161
|
|
|
case 'userid' : |
|
162
|
|
|
$cols['userid'] = esc_html__( 'User ID', 'give' ); |
|
163
|
|
|
break; |
|
164
|
|
|
case 'donation_form' : |
|
165
|
|
|
$cols['donation_form'] = esc_html__( 'Donation Form', 'give' ); |
|
166
|
|
|
break; |
|
167
|
|
|
case 'date_first_donated' : |
|
168
|
|
|
$cols['date_first_donated'] = esc_html__( 'First Donation Date', 'give' ); |
|
169
|
|
|
break; |
|
170
|
|
|
case 'donations' : |
|
171
|
|
|
$cols['donations'] = esc_html__( 'Number of Donations', 'give' ); |
|
172
|
|
|
break; |
|
173
|
|
|
case 'donation_sum' : |
|
174
|
|
|
$cols['donation_sum'] = esc_html__( 'Sum of Donations', 'give' ); |
|
175
|
|
|
break; |
|
176
|
|
|
} |
|
177
|
|
|
} |
|
178
|
|
|
|
|
179
|
|
|
return $cols; |
|
180
|
|
|
|
|
181
|
|
|
} |
|
182
|
|
|
|
|
183
|
|
|
/** |
|
184
|
|
|
* Get the Export Data |
|
185
|
|
|
* |
|
186
|
|
|
* @access public |
|
187
|
|
|
* @since 1.0 |
|
188
|
|
|
* @global object $give_logs Give Logs Object. |
|
189
|
|
|
* @return array $data The data for the CSV file. |
|
190
|
|
|
*/ |
|
191
|
|
|
public function get_data() { |
|
192
|
|
|
$i = 0; |
|
193
|
|
|
|
|
194
|
|
|
$data = array(); |
|
195
|
|
|
$cached_donor_ids = Give_Cache::get( $this->query_id, true ); |
|
196
|
|
|
|
|
197
|
|
|
if ( ! empty( $this->form ) ) { |
|
198
|
|
|
|
|
199
|
|
|
// Export donors for a specific donation form and also within specified timeframe |
|
200
|
|
|
$args = array( |
|
201
|
|
|
'output' => 'payments', // Use 'posts' to get standard post objects |
|
202
|
|
|
'post_type' => array( 'give_payment' ), |
|
203
|
|
|
'number' => 30, |
|
204
|
|
|
'paged' => $this->step, |
|
205
|
|
|
'status' => 'publish', |
|
206
|
|
|
'meta_key' => '_give_payment_form_id', |
|
207
|
|
|
'meta_value' => absint( $this->form ), |
|
208
|
|
|
); |
|
209
|
|
|
|
|
210
|
|
|
// Check for date option filter |
|
211
|
|
|
if ( ! empty( $this->data['donor_export_start_date'] ) || ! empty( $this->data['donor_export_end_date'] ) ) { |
|
212
|
|
|
$args['start_date'] = ! empty( $this->data['donor_export_start_date'] ) ? date( 'Y-n-d 00:00:00', strtotime( $this->data['donor_export_start_date'] ) ) : date( 'Y-n-d 23:59:59', '1970-1-01 00:00:00' ); |
|
213
|
|
|
$args['end_date'] = ! empty( $this->data['donor_export_end_date'] ) ? date( 'Y-n-d 23:59:59', strtotime( $this->data['donor_export_end_date'] ) ) : date( 'Y-n-d 23:59:59', current_time( 'timestamp' ) ); |
|
214
|
|
|
} |
|
215
|
|
|
|
|
216
|
|
|
// Check for price option. |
|
217
|
|
|
if ( null !== $this->price_id ) { |
|
218
|
|
|
$args['meta_query'] = array( |
|
219
|
|
|
array( |
|
220
|
|
|
'key' => '_give_payment_price_id', |
|
221
|
|
|
'value' => (int) $this->price_id, |
|
222
|
|
|
), |
|
223
|
|
|
); |
|
224
|
|
|
} |
|
225
|
|
|
|
|
226
|
|
|
$payments_query = new Give_Payments_Query( $args ); |
|
227
|
|
|
$payments = $payments_query->get_payments(); |
|
228
|
|
|
|
|
229
|
|
|
if ( $payments ) { |
|
|
|
|
|
|
230
|
|
|
/* @var Give_Payment $payment */ |
|
231
|
|
|
foreach ( $payments as $payment ) { |
|
232
|
|
|
// Set donation sum. |
|
233
|
|
|
$this->payment_stats[ $payment->customer_id ]['donation_sum'] = isset( $this->payment_stats[ $payment->customer_id ]['donation_sum'] ) ? |
|
234
|
|
|
$this->payment_stats[ $payment->customer_id ]['donation_sum'] : |
|
235
|
|
|
0; |
|
236
|
|
|
$this->payment_stats[ $payment->customer_id ]['donation_sum'] += $payment->total; |
|
237
|
|
|
|
|
238
|
|
|
// Set donation count. |
|
239
|
|
|
$this->payment_stats[ $payment->customer_id ]['donations'] = isset( $this->payment_stats[ $payment->customer_id ]['donations'] ) ? |
|
240
|
|
|
++ $this->payment_stats[ $payment->customer_id ]['donations'] : |
|
241
|
|
|
1; |
|
242
|
|
|
|
|
243
|
|
|
// Set donation form name. |
|
244
|
|
|
$this->payment_stats[ $payment->customer_id ]['form_title'] = $payment->form_title; |
|
245
|
|
|
|
|
246
|
|
|
// Continue if donor already included. |
|
247
|
|
|
if ( empty( $payment->customer_id ) || |
|
248
|
|
|
in_array( $payment->customer_id, $cached_donor_ids ) |
|
249
|
|
|
) { |
|
250
|
|
|
continue; |
|
251
|
|
|
} |
|
252
|
|
|
|
|
253
|
|
|
$this->donor_ids[] = $cached_donor_ids[] = $payment->customer_id; |
|
254
|
|
|
|
|
255
|
|
|
$i ++; |
|
256
|
|
|
} |
|
257
|
|
|
|
|
258
|
|
|
if ( ! empty( $this->donor_ids ) ) { |
|
259
|
|
|
foreach ( $this->donor_ids as $donor_id ) { |
|
260
|
|
|
$donor = Give()->donors->get_donor_by( 'id', $donor_id ); |
|
261
|
|
|
$donor->donation_form_title = $this->payment_stats[ $donor_id ]['form_title']; |
|
262
|
|
|
$donor->purchase_count = $this->payment_stats[ $donor_id ]['donations']; |
|
263
|
|
|
$donor->purchase_value = $this->payment_stats[ $donor_id ]['donation_sum']; |
|
264
|
|
|
$data[] = $this->set_donor_data( $i, $data, $donor ); |
|
265
|
|
|
} |
|
266
|
|
|
|
|
267
|
|
|
// Cache donor ids only if admin export donor for specific form. |
|
268
|
|
|
$this->cache_donor_ids(); |
|
269
|
|
|
} |
|
270
|
|
|
} |
|
271
|
|
|
} else { |
|
272
|
|
|
|
|
273
|
|
|
// Export all donors. |
|
274
|
|
|
$offset = 30 * ( $this->step - 1 ); |
|
275
|
|
|
|
|
276
|
|
|
$args = array( |
|
277
|
|
|
'number' => 30, |
|
278
|
|
|
'offset' => $offset, |
|
279
|
|
|
); |
|
280
|
|
|
|
|
281
|
|
|
// Check for date option filter |
|
282
|
|
|
if ( ! empty( $this->data['donor_export_start_date'] ) || ! empty( $this->data['donor_export_end_date'] ) ) { |
|
283
|
|
|
$args['date'] = array( |
|
284
|
|
|
'start' => ! empty( $this->data['donor_export_start_date'] ) ? date( 'Y-n-d 00:00:00', strtotime( $this->data['donor_export_start_date'] ) ) : date( 'Y-n-d 23:59:59', '1970-1-01 00:00:00' ), |
|
285
|
|
|
'end' => ! empty( $this->data['donor_export_end_date'] ) ? date( 'Y-n-d 23:59:59', strtotime( $this->data['donor_export_end_date'] ) ) : date( 'Y-n-d 23:59:59', current_time( 'timestamp' ) ), |
|
286
|
|
|
); |
|
287
|
|
|
} |
|
288
|
|
|
|
|
289
|
|
|
$donors = Give()->donors->get_donors( $args ); |
|
290
|
|
|
|
|
291
|
|
|
foreach ( $donors as $donor ) { |
|
|
|
|
|
|
292
|
|
|
|
|
293
|
|
|
// Continue if donor already included. |
|
294
|
|
|
if ( empty( $donor->id ) || empty( $donor->payment_ids ) ) { |
|
295
|
|
|
continue; |
|
296
|
|
|
} |
|
297
|
|
|
|
|
298
|
|
|
$payment = new Give_Payment( $donor->payment_ids ); |
|
299
|
|
|
$donor->donation_form_title = $payment->form_title; |
|
300
|
|
|
$data[] = $this->set_donor_data( $i, $data, $donor ); |
|
301
|
|
|
$i ++; |
|
302
|
|
|
} |
|
303
|
|
|
}// End if(). |
|
|
|
|
|
|
304
|
|
|
|
|
305
|
|
|
$data = apply_filters( 'give_export_get_data', $data ); |
|
306
|
|
|
$data = apply_filters( "give_export_get_data_{$this->export_type}", $data ); |
|
307
|
|
|
|
|
308
|
|
|
return $data; |
|
309
|
|
|
} |
|
310
|
|
|
|
|
311
|
|
|
/** |
|
312
|
|
|
* Return the calculated completion percentage. |
|
313
|
|
|
* |
|
314
|
|
|
* @since 1.5 |
|
315
|
|
|
* @return int |
|
|
|
|
|
|
316
|
|
|
*/ |
|
317
|
|
|
public function get_percentage_complete() { |
|
318
|
|
|
|
|
319
|
|
|
$percentage = 0; |
|
320
|
|
|
|
|
321
|
|
|
// We can't count the number when getting them for a specific form. |
|
322
|
|
|
if ( empty( $this->form ) ) { |
|
323
|
|
|
|
|
324
|
|
|
$total = Give()->donors->count(); |
|
325
|
|
|
|
|
326
|
|
|
if ( $total > 0 ) { |
|
327
|
|
|
|
|
328
|
|
|
$percentage = ( ( 30 * $this->step ) / $total ) * 100; |
|
329
|
|
|
|
|
330
|
|
|
} |
|
331
|
|
|
} |
|
332
|
|
|
|
|
333
|
|
|
if ( $percentage > 100 ) { |
|
334
|
|
|
$percentage = 100; |
|
335
|
|
|
} |
|
336
|
|
|
|
|
337
|
|
|
return $percentage; |
|
338
|
|
|
} |
|
339
|
|
|
|
|
340
|
|
|
/** |
|
341
|
|
|
* Set Donor Data |
|
342
|
|
|
* |
|
343
|
|
|
* @param int $i |
|
344
|
|
|
* @param array $data |
|
345
|
|
|
* @param Give_Donor $donor |
|
346
|
|
|
* |
|
347
|
|
|
* @return mixed |
|
348
|
|
|
*/ |
|
349
|
|
|
private function set_donor_data( $i, $data, $donor ) { |
|
350
|
|
|
|
|
351
|
|
|
$columns = $this->csv_cols(); |
|
352
|
|
|
|
|
353
|
|
|
// Set address variable |
|
354
|
|
|
$address = ''; |
|
355
|
|
|
if ( isset( $donor->user_id ) && $donor->user_id > 0 ) { |
|
356
|
|
|
$address = give_get_donor_address( $donor->user_id ); |
|
357
|
|
|
} |
|
358
|
|
|
|
|
359
|
|
|
// Set columns |
|
360
|
|
|
if ( ! empty( $columns['full_name'] ) ) { |
|
361
|
|
|
$data[ $i ]['full_name'] = $donor->name; |
|
362
|
|
|
} |
|
363
|
|
|
if ( ! empty( $columns['email'] ) ) { |
|
364
|
|
|
$data[ $i ]['email'] = $donor->email; |
|
365
|
|
|
} |
|
366
|
|
|
if ( ! empty( $columns['address_line1'] ) ) { |
|
367
|
|
|
|
|
368
|
|
|
$data[ $i ]['address_line1'] = isset( $address['line1'] ) ? $address['line1'] : ''; |
|
369
|
|
|
$data[ $i ]['address_line2'] = isset( $address['line2'] ) ? $address['line2'] : ''; |
|
370
|
|
|
$data[ $i ]['address_city'] = isset( $address['city'] ) ? $address['city'] : ''; |
|
371
|
|
|
$data[ $i ]['address_state'] = isset( $address['state'] ) ? $address['state'] : ''; |
|
372
|
|
|
$data[ $i ]['address_zip'] = isset( $address['zip'] ) ? $address['zip'] : ''; |
|
373
|
|
|
$data[ $i ]['address_country'] = isset( $address['country'] ) ? $address['country'] : ''; |
|
374
|
|
|
} |
|
375
|
|
|
if ( ! empty( $columns['userid'] ) ) { |
|
376
|
|
|
$data[ $i ]['userid'] = ! empty( $donor->user_id ) ? $donor->user_id : ''; |
|
377
|
|
|
} |
|
378
|
|
|
if ( ! empty( $columns['donation_form'] ) ) { |
|
379
|
|
|
$data[ $i ]['donation_form'] = ! empty( $donor->donation_form_title ) ? $donor->donation_form_title : ''; |
|
|
|
|
|
|
380
|
|
|
} |
|
381
|
|
|
if ( ! empty( $columns['date_first_donated'] ) ) { |
|
382
|
|
|
$data[ $i ]['date_first_donated'] = date_i18n( give_date_format(), strtotime( $donor->date_created ) ); |
|
383
|
|
|
} |
|
384
|
|
|
if ( ! empty( $columns['donations'] ) ) { |
|
385
|
|
|
$data[ $i ]['donations'] = $donor->purchase_count; |
|
386
|
|
|
} |
|
387
|
|
|
if ( ! empty( $columns['donation_sum'] ) ) { |
|
388
|
|
|
$data[ $i ]['donation_sum'] = give_format_amount( $donor->purchase_value ); |
|
389
|
|
|
} |
|
390
|
|
|
|
|
391
|
|
|
return $data[ $i ]; |
|
392
|
|
|
|
|
393
|
|
|
} |
|
394
|
|
|
|
|
395
|
|
|
/** |
|
396
|
|
|
* Unset the properties specific to the donors export. |
|
397
|
|
|
* |
|
398
|
|
|
* @param array $request |
|
399
|
|
|
* @param Give_Batch_Export $export |
|
400
|
|
|
*/ |
|
401
|
|
|
public function unset_properties( $request, $export ) { |
|
402
|
|
|
if ( $export->done ) { |
|
403
|
|
|
Give_Cache::delete( "give_cache_{$this->query_id}" ); |
|
404
|
|
|
} |
|
405
|
|
|
} |
|
406
|
|
|
} |
|
407
|
|
|
|
The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.
The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.
To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.