1
|
|
|
<?php |
|
|
|
|
2
|
|
|
/** |
3
|
|
|
* Recount all donation counts and income stats |
4
|
|
|
* |
5
|
|
|
* This class handles batch processing of recounting donations and income stat totals |
6
|
|
|
* |
7
|
|
|
* @subpackage Admin/Tools/Give_Tools_Recount_All_Stats |
8
|
|
|
* @copyright Copyright (c) 2016, WordImpress |
9
|
|
|
* @license https://opensource.org/licenses/gpl-license GNU Public License |
10
|
|
|
* @since 1.5 |
11
|
|
|
*/ |
12
|
|
|
|
13
|
|
|
// Exit if accessed directly. |
14
|
|
|
if (! defined('ABSPATH') ) { |
15
|
|
|
exit; |
16
|
|
|
} |
17
|
|
|
|
18
|
|
|
/** |
19
|
|
|
* Give_Tools_Recount_All_Stats Class |
20
|
|
|
* |
21
|
|
|
* @since 1.5 |
22
|
|
|
*/ |
23
|
|
|
class Give_Tools_Recount_All_Stats extends Give_Batch_Export { |
24
|
|
|
|
25
|
|
|
/** |
26
|
|
|
* Our export type. Used for export-type specific filters/actions |
27
|
|
|
* |
28
|
|
|
* @since 1.5 |
29
|
|
|
* @var string |
30
|
|
|
*/ |
31
|
|
|
public $export_type = ''; |
32
|
|
|
|
33
|
|
|
/** |
34
|
|
|
* Allows for a non-form batch processing to be run. |
35
|
|
|
* |
36
|
|
|
* @since 1.5 |
37
|
|
|
* @var bool |
38
|
|
|
*/ |
39
|
|
|
public $is_void = true; |
40
|
|
|
|
41
|
|
|
/** |
42
|
|
|
* Sets the number of items to pull on each step |
43
|
|
|
* |
44
|
|
|
* @since 1.5 |
45
|
|
|
* @var int |
46
|
|
|
*/ |
47
|
|
|
public $per_step = 30; |
48
|
|
|
|
49
|
|
|
/** |
50
|
|
|
* Display message on completing recount process |
51
|
|
|
* |
52
|
|
|
* @since 1.8.9 |
53
|
|
|
* @var string |
54
|
|
|
*/ |
55
|
|
|
public $message = ''; |
56
|
|
|
|
57
|
|
|
/** |
58
|
|
|
* Sets donation form id for recalculation |
59
|
|
|
* |
60
|
|
|
* @since 1.8.9 |
61
|
|
|
* @var int |
62
|
|
|
*/ |
63
|
|
|
protected $form_id = 0; |
64
|
|
|
|
65
|
|
|
/** |
66
|
|
|
* Is Recount process completed |
67
|
|
|
* |
68
|
|
|
* @since 1.8.9 |
69
|
|
|
* @var bool |
70
|
|
|
*/ |
71
|
|
|
public $done = false; |
72
|
|
|
|
73
|
|
|
/** |
74
|
|
|
* Get the recount all stats data |
75
|
|
|
* |
76
|
|
|
* @access public |
77
|
|
|
* @since 1.5 |
78
|
|
|
* |
79
|
|
|
* @return bool |
80
|
|
|
*/ |
81
|
|
|
public function get_data() { |
82
|
|
|
|
83
|
|
|
$totals = $this->get_stored_data( 'give_temp_recount_all_stats' ); |
84
|
|
|
$payment_items = $this->get_stored_data( 'give_temp_payment_items' ); |
85
|
|
|
$processed_payments = $this->get_stored_data( 'give_temp_processed_payments' ); |
86
|
|
|
$accepted_statuses = apply_filters( 'give_recount_accepted_statuses', array( 'publish' ) ); |
87
|
|
|
|
88
|
|
|
if ( false === $totals ) { |
89
|
|
|
$totals = array(); |
90
|
|
|
} |
91
|
|
|
|
92
|
|
|
if ( false === $payment_items ) { |
93
|
|
|
$payment_items = array(); |
94
|
|
|
} |
95
|
|
|
|
96
|
|
|
if ( false === $processed_payments ) { |
97
|
|
|
$processed_payments = array(); |
98
|
|
|
} |
99
|
|
|
|
100
|
|
|
$all_forms = $this->get_stored_data( 'give_temp_form_ids' ); |
101
|
|
|
|
102
|
|
|
$payments = $this->get_stored_data( 'give_temp_all_payments_data' ); |
103
|
|
|
|
104
|
|
|
if( false === $payments ) { |
105
|
|
|
$args = apply_filters( 'give_recount_form_stats_args', array( |
106
|
|
|
'post_parent__in' => $all_forms, |
107
|
|
|
'number' => $this->per_step, |
108
|
|
|
'status' => 'publish', |
109
|
|
|
'paged' => $this->step, |
110
|
|
|
'output' => 'payments', |
111
|
|
|
) ); |
112
|
|
|
|
113
|
|
|
$payments_query = new Give_Payments_Query( $args ); |
114
|
|
|
$payments = $payments_query->get_payments(); |
115
|
|
|
} |
116
|
|
|
|
117
|
|
|
if ( $payments ) { |
118
|
|
|
|
119
|
|
|
//Loop through payments |
120
|
|
|
foreach ( $payments as $payment ) { |
121
|
|
|
|
122
|
|
|
// Prevent payments that have all ready been retrieved from a previous sales log from counting again. |
123
|
|
|
if ( in_array( $payment->ID, $processed_payments ) ) { |
124
|
|
|
continue; |
125
|
|
|
} |
126
|
|
|
|
127
|
|
|
// Verify accepted status |
128
|
|
|
if ( ! in_array( $payment->post_status, $accepted_statuses ) ) { |
129
|
|
|
$processed_payments[] = $payment->ID; |
130
|
|
|
continue; |
131
|
|
|
} |
132
|
|
|
|
133
|
|
|
$payment_item = $payment_items[ $payment->ID ]; |
134
|
|
|
|
135
|
|
|
$form_id = isset( $payment_item['id'] ) ? $payment_item['id'] : ''; |
136
|
|
|
|
137
|
|
|
//Must have a form ID |
138
|
|
|
if ( empty( $form_id ) ) { |
139
|
|
|
continue; |
140
|
|
|
} |
141
|
|
|
|
142
|
|
|
//Form ID must be within $all_forms array to be validated |
143
|
|
|
if ( ! in_array( $form_id, $all_forms ) ) { |
144
|
|
|
continue; |
145
|
|
|
} |
146
|
|
|
|
147
|
|
|
// Set Sales count |
148
|
|
|
$totals[ $form_id ]['sales'] = isset( $totals[ $form_id ]['sales'] ) ? |
149
|
|
|
++ $totals[ $form_id ]['sales'] : |
150
|
|
|
1; |
151
|
|
|
|
152
|
|
|
// Set Total Earnings |
153
|
|
|
$totals[ $form_id ]['earnings'] = isset( $totals[ $form_id ]['earnings'] ) ? |
154
|
|
|
( $totals[ $form_id ]['earnings'] + $payment_item['price'] ) : |
155
|
|
|
$payment_item['price']; |
156
|
|
|
|
157
|
|
|
$processed_payments[] = $payment->ID; |
158
|
|
|
} |
159
|
|
|
|
160
|
|
|
// Get the list of form ids which does not contain any payment record. |
161
|
|
|
$remaining_form_ids = array_diff( $all_forms, array_keys($totals) ); |
162
|
|
|
foreach( $remaining_form_ids as $form_id) { |
163
|
|
|
//If array key doesn't exist, create it |
164
|
|
|
if ( ! array_key_exists( $form_id, $totals ) ) { |
165
|
|
|
$totals[ $form_id ] = array( |
166
|
|
|
'sales' => (int) 0, |
167
|
|
|
'earnings' => (float) 0, |
168
|
|
|
); |
169
|
|
|
} |
170
|
|
|
} |
171
|
|
|
|
172
|
|
|
$this->store_data( 'give_temp_processed_payments', $processed_payments ); |
173
|
|
|
$this->store_data( 'give_temp_recount_all_stats', $totals ); |
174
|
|
|
|
175
|
|
|
return true; |
176
|
|
|
} |
177
|
|
|
|
178
|
|
|
foreach ( $totals as $key => $stats ) { |
179
|
|
|
give_update_meta( $key, '_give_form_sales', $stats['sales'] ); |
180
|
|
|
give_update_meta( $key, '_give_form_earnings', $stats['earnings'] ); |
181
|
|
|
} |
182
|
|
|
|
183
|
|
|
return false; |
184
|
|
|
|
185
|
|
|
} |
186
|
|
|
|
187
|
|
|
/** |
188
|
|
|
* Return the calculated completion percentage |
189
|
|
|
* |
190
|
|
|
* @since 1.5 |
191
|
|
|
* @return int |
|
|
|
|
192
|
|
|
*/ |
193
|
|
|
public function get_percentage_complete() { |
194
|
|
|
|
195
|
|
|
$total = $this->get_stored_data( 'give_recount_all_total' ); |
196
|
|
|
|
197
|
|
|
if ( false === $total ) { |
198
|
|
|
$this->pre_fetch(); |
199
|
|
|
$total = $this->get_stored_data( 'give_recount_all_total' ); |
200
|
|
|
} |
201
|
|
|
|
202
|
|
|
$percentage = 100; |
203
|
|
|
|
204
|
|
|
if ( $total > 0 ) { |
205
|
|
|
$percentage = ( ( $this->per_step * $this->step ) / $total ) * 100; |
206
|
|
|
} |
207
|
|
|
|
208
|
|
|
if ( $percentage > 100 ) { |
209
|
|
|
$percentage = 100; |
210
|
|
|
} |
211
|
|
|
|
212
|
|
|
return $percentage; |
213
|
|
|
} |
214
|
|
|
|
215
|
|
|
/** |
216
|
|
|
* Set the properties specific to the payments export |
217
|
|
|
* |
218
|
|
|
* @since 1.5 |
219
|
|
|
* |
220
|
|
|
* @param array $request The Form Data passed into the batch processing |
221
|
|
|
*/ |
222
|
|
|
public function set_properties( $request ) { |
223
|
|
|
$this->form_id = isset( $request['form_id'] ) ? sanitize_text_field( $request['form_id'] ) : false; |
224
|
|
|
} |
225
|
|
|
|
226
|
|
|
/** |
227
|
|
|
* Process a step |
228
|
|
|
* |
229
|
|
|
* @since 1.5 |
230
|
|
|
* @return bool |
231
|
|
|
*/ |
232
|
|
|
public function process_step() { |
233
|
|
|
|
234
|
|
|
if ( ! $this->can_export() ) { |
235
|
|
|
wp_die( esc_html__( 'You do not have permission to recount stats.', 'give' ), esc_html__( 'Error', 'give' ), array( 'response' => 403 ) ); |
236
|
|
|
} |
237
|
|
|
|
238
|
|
|
$had_data = $this->get_data(); |
239
|
|
|
|
240
|
|
|
if ( $had_data ) { |
241
|
|
|
$this->done = false; |
242
|
|
|
|
243
|
|
|
return true; |
244
|
|
|
} else { |
245
|
|
|
$this->delete_data( 'give_recount_total_' . $this->form_id ); |
246
|
|
|
$this->delete_data( 'give_recount_all_total' ); |
247
|
|
|
$this->delete_data( 'give_temp_recount_all_stats' ); |
248
|
|
|
$this->delete_data( 'give_temp_payment_items' ); |
249
|
|
|
$this->delete_data( 'give_temp_form_ids' ); |
250
|
|
|
$this->delete_data( 'give_temp_processed_payments' ); |
251
|
|
|
$this->done = true; |
252
|
|
|
$this->message = esc_html__( 'Donation form income amounts and donation counts stats successfully recounted.', 'give' ); |
253
|
|
|
|
254
|
|
|
return false; |
255
|
|
|
} |
256
|
|
|
} |
257
|
|
|
|
258
|
|
|
public function headers() { |
259
|
|
|
ignore_user_abort( true ); |
260
|
|
|
|
261
|
|
|
if ( ! give_is_func_disabled( 'set_time_limit' ) && ! ini_get( 'safe_mode' ) ) { |
262
|
|
|
set_time_limit( 0 ); |
263
|
|
|
} |
264
|
|
|
} |
265
|
|
|
|
266
|
|
|
/** |
267
|
|
|
* Perform the export |
268
|
|
|
* |
269
|
|
|
* @access public |
270
|
|
|
* @since 1.5 |
271
|
|
|
* @return void |
272
|
|
|
*/ |
273
|
|
|
public function export() { |
274
|
|
|
|
275
|
|
|
// Set headers |
276
|
|
|
$this->headers(); |
277
|
|
|
|
278
|
|
|
give_die(); |
279
|
|
|
} |
280
|
|
|
|
281
|
|
|
/** |
282
|
|
|
* Pre Fetch Data |
283
|
|
|
* |
284
|
|
|
* @access public |
285
|
|
|
* @since 1.5 |
286
|
|
|
*/ |
287
|
|
|
public function pre_fetch() { |
288
|
|
|
|
289
|
|
|
if ( $this->step == 1 ) { |
290
|
|
|
$this->delete_data( 'give_temp_recount_all_total' ); |
291
|
|
|
$this->delete_data( 'give_temp_recount_all_stats' ); |
292
|
|
|
$this->delete_data( 'give_temp_payment_items' ); |
293
|
|
|
$this->delete_data( 'give_temp_processed_payments' ); |
294
|
|
|
$this->delete_data( 'give_temp_all_payments_data' ); |
295
|
|
|
} |
296
|
|
|
|
297
|
|
|
$accepted_statuses = apply_filters( 'give_recount_accepted_statuses', array( 'publish' ) ); |
298
|
|
|
$total = $this->get_stored_data( 'give_temp_recount_all_total' ); |
299
|
|
|
|
300
|
|
|
if ( false === $total ) { |
301
|
|
|
$total = 0; |
302
|
|
|
$payment_items = $this->get_stored_data( 'give_temp_payment_items' ); |
303
|
|
|
|
304
|
|
|
if ( false === $payment_items ) { |
305
|
|
|
$payment_items = array(); |
306
|
|
|
$this->store_data( 'give_temp_payment_items', $payment_items ); |
307
|
|
|
} |
308
|
|
|
|
309
|
|
|
$args = array( |
310
|
|
|
'post_status' => 'publish', |
311
|
|
|
'post_type' => 'give_forms', |
312
|
|
|
'posts_per_page' => - 1, |
313
|
|
|
'fields' => 'ids', |
314
|
|
|
); |
315
|
|
|
|
316
|
|
|
$all_forms = get_posts( $args ); |
317
|
|
|
$this->store_data( 'give_temp_form_ids', $all_forms ); |
318
|
|
|
|
319
|
|
|
$args = apply_filters( 'give_recount_form_stats_total_args', array( |
320
|
|
|
'post_parent__in' => $all_forms, |
321
|
|
|
'number' => $this->per_step, |
322
|
|
|
'status' => 'publish', |
323
|
|
|
'page' => $this->step, |
324
|
|
|
'output' => 'payments', |
325
|
|
|
) ); |
326
|
|
|
|
327
|
|
|
$payments_query = new Give_Payments_Query( $args ); |
328
|
|
|
$payments = $payments_query->get_payments(); |
329
|
|
|
$total = wp_count_posts( 'give_payment' )->publish; |
330
|
|
|
|
331
|
|
|
$this->store_data( 'give_temp_all_payments_data', $payments ); |
332
|
|
|
|
333
|
|
|
if ( $payments ) { |
|
|
|
|
334
|
|
|
|
335
|
|
|
foreach ( $payments as $payment ) { |
336
|
|
|
|
337
|
|
|
$payment = new Give_Payment( $payment->ID ); |
338
|
|
|
$form_id = $payment->form_id; |
339
|
|
|
|
340
|
|
|
//If for some reason somehow the form_ID isn't set check payment meta |
341
|
|
|
if ( empty( $payment->form_id ) ) { |
342
|
|
|
$payment_meta = $payment->get_meta(); |
343
|
|
|
$form_id = isset( $payment_meta['form_id'] ) ? $payment_meta['form_id'] : 0; |
344
|
|
|
} |
345
|
|
|
|
346
|
|
|
if ( ! in_array( $payment->post_status, $accepted_statuses ) ) { |
347
|
|
|
continue; |
348
|
|
|
} |
349
|
|
|
|
350
|
|
|
if ( ! array_key_exists( $payment->ID, $payment_items ) ) { |
351
|
|
|
$payment_items[ $payment->ID ] = array( |
352
|
|
|
'id' => $form_id, |
353
|
|
|
'payment_id' => $payment->ID, |
354
|
|
|
'price' => $payment->total |
355
|
|
|
); |
356
|
|
|
} |
357
|
|
|
|
358
|
|
|
} |
359
|
|
|
|
360
|
|
|
} |
361
|
|
|
|
362
|
|
|
$this->store_data( 'give_temp_payment_items', $payment_items ); |
363
|
|
|
$this->store_data( 'give_recount_all_total', $total ); |
364
|
|
|
} |
365
|
|
|
|
366
|
|
|
} |
367
|
|
|
|
368
|
|
|
/** |
369
|
|
|
* Given a key, get the information from the Database Directly |
370
|
|
|
* |
371
|
|
|
* @since 1.5 |
372
|
|
|
* |
373
|
|
|
* @param string $key The option_name |
374
|
|
|
* |
375
|
|
|
* @return mixed Returns the data from the database |
376
|
|
|
*/ |
377
|
|
|
private function get_stored_data( $key ) { |
378
|
|
|
global $wpdb; |
|
|
|
|
379
|
|
|
$value = $wpdb->get_var( $wpdb->prepare( "SELECT option_value FROM $wpdb->options WHERE option_name = '%s'", $key ) ); |
380
|
|
|
|
381
|
|
|
return empty( $value ) ? false : maybe_unserialize( $value ); |
382
|
|
|
} |
383
|
|
|
|
384
|
|
|
/** |
385
|
|
|
* Give a key, store the value |
386
|
|
|
* |
387
|
|
|
* @since 1.5 |
388
|
|
|
* |
389
|
|
|
* @param string $key The option_name |
390
|
|
|
* @param mixed $value The value to store |
391
|
|
|
* |
392
|
|
|
* @return void |
393
|
|
|
*/ |
394
|
|
|
private function store_data( $key, $value ) { |
395
|
|
|
global $wpdb; |
|
|
|
|
396
|
|
|
|
397
|
|
|
$value = maybe_serialize( $value ); |
398
|
|
|
|
399
|
|
|
$data = array( |
400
|
|
|
'option_name' => $key, |
401
|
|
|
'option_value' => $value, |
402
|
|
|
'autoload' => 'no', |
403
|
|
|
); |
404
|
|
|
|
405
|
|
|
$formats = array( |
406
|
|
|
'%s', |
407
|
|
|
'%s', |
408
|
|
|
'%s', |
409
|
|
|
); |
410
|
|
|
|
411
|
|
|
$wpdb->replace( $wpdb->options, $data, $formats ); |
412
|
|
|
} |
413
|
|
|
|
414
|
|
|
/** |
415
|
|
|
* Delete an option |
416
|
|
|
* |
417
|
|
|
* @since 1.5 |
418
|
|
|
* |
419
|
|
|
* @param string $key The option_name to delete |
420
|
|
|
* |
421
|
|
|
* @return void |
422
|
|
|
*/ |
423
|
|
|
private function delete_data( $key ) { |
424
|
|
|
global $wpdb; |
|
|
|
|
425
|
|
|
$wpdb->delete( $wpdb->options, array( 'option_name' => $key ) ); |
426
|
|
|
} |
427
|
|
|
|
428
|
|
|
} |
429
|
|
|
|
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.