1
|
|
|
<?php |
|
|
|
|
2
|
|
|
/** |
3
|
|
|
* Give API |
4
|
|
|
* |
5
|
|
|
* A front-facing JSON/XML API that makes it possible to query donation data. |
6
|
|
|
* |
7
|
|
|
* @package Give |
8
|
|
|
* @subpackage Classes/API |
9
|
|
|
* @copyright Copyright (c) 2016, WordImpress |
10
|
|
|
* @license http://opensource.org/licenses/gpl-2.0.php GNU Public License |
11
|
|
|
* @since 1.1 |
12
|
|
|
*/ |
13
|
|
|
|
14
|
|
|
// Exit if accessed directly |
15
|
|
|
if ( ! defined( 'ABSPATH' ) ) { |
16
|
|
|
exit; |
17
|
|
|
} |
18
|
|
|
|
19
|
|
|
/** |
20
|
|
|
* Give_API Class |
21
|
|
|
* |
22
|
|
|
* Renders API returns as a JSON/XML array |
23
|
|
|
* |
24
|
|
|
* @since 1.1 |
25
|
|
|
*/ |
26
|
|
|
class Give_API { |
27
|
|
|
|
28
|
|
|
/** |
29
|
|
|
* Latest API Version |
30
|
|
|
*/ |
31
|
|
|
const VERSION = 1; |
32
|
|
|
|
33
|
|
|
/** |
34
|
|
|
* Pretty Print? |
35
|
|
|
* |
36
|
|
|
* @var bool |
37
|
|
|
* @access private |
38
|
|
|
* @since 1.1 |
39
|
|
|
*/ |
40
|
|
|
private $pretty_print = false; |
41
|
|
|
|
42
|
|
|
/** |
43
|
|
|
* Log API requests? |
44
|
|
|
* |
45
|
|
|
* @var bool |
46
|
|
|
* @access private |
47
|
|
|
* @since 1.1 |
48
|
|
|
*/ |
49
|
|
|
public $log_requests = true; |
50
|
|
|
|
51
|
|
|
/** |
52
|
|
|
* Is this a valid request? |
53
|
|
|
* |
54
|
|
|
* @var bool |
55
|
|
|
* @access private |
56
|
|
|
* @since 1.1 |
57
|
|
|
*/ |
58
|
|
|
private $is_valid_request = false; |
59
|
|
|
|
60
|
|
|
/** |
61
|
|
|
* User ID Performing the API Request |
62
|
|
|
* |
63
|
|
|
* @var int |
64
|
|
|
* @access private |
65
|
|
|
* @since 1.1 |
66
|
|
|
*/ |
67
|
|
|
public $user_id = 0; |
68
|
|
|
|
69
|
|
|
/** |
70
|
|
|
* Instance of Give Stats class |
71
|
|
|
* |
72
|
|
|
* @var object |
73
|
|
|
* @access private |
74
|
|
|
* @since 1.1 |
75
|
|
|
*/ |
76
|
|
|
private $stats; |
77
|
|
|
|
78
|
|
|
/** |
79
|
|
|
* Response data to return |
80
|
|
|
* |
81
|
|
|
* @var array |
82
|
|
|
* @access private |
83
|
|
|
* @since 1.1 |
84
|
|
|
*/ |
85
|
|
|
private $data = array(); |
86
|
|
|
|
87
|
|
|
/** |
88
|
|
|
* |
89
|
|
|
* @var bool |
90
|
|
|
* @access private |
91
|
|
|
* @since 1.1 |
92
|
|
|
*/ |
93
|
|
|
public $override = true; |
94
|
|
|
|
95
|
|
|
/** |
96
|
|
|
* Version of the API queried |
97
|
|
|
* |
98
|
|
|
* @var string |
99
|
|
|
* @access public |
100
|
|
|
* @since 1.1 |
101
|
|
|
*/ |
102
|
|
|
private $queried_version; |
103
|
|
|
|
104
|
|
|
/** |
105
|
|
|
* All versions of the API |
106
|
|
|
* |
107
|
|
|
* @var string |
108
|
|
|
* @access public |
109
|
|
|
* @since 1.1 |
110
|
|
|
*/ |
111
|
|
|
protected $versions = array(); |
112
|
|
|
|
113
|
|
|
/** |
114
|
|
|
* Queried endpoint |
115
|
|
|
* |
116
|
|
|
* @var string |
117
|
|
|
* @access public |
118
|
|
|
* @since 1.1 |
119
|
|
|
*/ |
120
|
|
|
private $endpoint; |
121
|
|
|
|
122
|
|
|
/** |
123
|
|
|
* Endpoints routes |
124
|
|
|
* |
125
|
|
|
* @var object |
126
|
|
|
* @access public |
127
|
|
|
* @since 1.1 |
128
|
|
|
*/ |
129
|
|
|
private $routes; |
130
|
|
|
|
131
|
|
|
/** |
132
|
|
|
* Setup the Give API |
133
|
|
|
* |
134
|
|
|
* @since 1.1 |
135
|
|
|
*/ |
136
|
12 |
|
public function __construct() { |
137
|
|
|
|
138
|
12 |
|
$this->versions = array( |
139
|
12 |
|
'v1' => 'GIVE_API_V1', |
140
|
|
|
); |
141
|
|
|
|
142
|
12 |
|
foreach ( $this->get_versions() as $version => $class ) { |
|
|
|
|
143
|
12 |
|
require_once GIVE_PLUGIN_DIR . 'includes/api/class-give-api-' . $version . '.php'; |
144
|
12 |
|
} |
145
|
|
|
|
146
|
12 |
|
add_action( 'init', array( $this, 'add_endpoint' ) ); |
147
|
12 |
|
add_action( 'wp', array( $this, 'process_query' ), - 1 ); |
148
|
12 |
|
add_filter( 'query_vars', array( $this, 'query_vars' ) ); |
149
|
12 |
|
add_action( 'show_user_profile', array( $this, 'user_key_field' ) ); |
150
|
12 |
|
add_action( 'edit_user_profile', array( $this, 'user_key_field' ) ); |
151
|
12 |
|
add_action( 'personal_options_update', array( $this, 'update_key' ) ); |
152
|
12 |
|
add_action( 'edit_user_profile_update', array( $this, 'update_key' ) ); |
153
|
12 |
|
add_action( 'give_process_api_key', array( $this, 'process_api_key' ) ); |
154
|
|
|
|
155
|
|
|
// Setup a backwards compatibility check for user API Keys |
156
|
12 |
|
add_filter( 'get_user_metadata', array( $this, 'api_key_backwards_compat' ), 10, 4 ); |
157
|
|
|
|
158
|
|
|
// Determine if JSON_PRETTY_PRINT is available |
159
|
12 |
|
$this->pretty_print = defined( 'JSON_PRETTY_PRINT' ) ? JSON_PRETTY_PRINT : null; |
160
|
|
|
|
161
|
|
|
// Allow API request logging to be turned off |
162
|
12 |
|
$this->log_requests = apply_filters( 'give_api_log_requests', $this->log_requests ); |
163
|
|
|
|
164
|
|
|
// Setup Give_Payment_Stats instance |
165
|
12 |
|
$this->stats = new Give_Payment_Stats; |
166
|
|
|
|
167
|
12 |
|
} |
168
|
|
|
|
169
|
|
|
/** |
170
|
|
|
* Registers a new rewrite endpoint for accessing the API |
171
|
|
|
* |
172
|
|
|
* @access public |
173
|
|
|
* |
174
|
|
|
* @param array $rewrite_rules WordPress Rewrite Rules |
175
|
|
|
* |
176
|
|
|
* @since 1.1 |
177
|
|
|
*/ |
178
|
10 |
|
public function add_endpoint( $rewrite_rules ) { |
|
|
|
|
179
|
10 |
|
add_rewrite_endpoint( 'give-api', EP_ALL ); |
180
|
10 |
|
} |
181
|
|
|
|
182
|
|
|
/** |
183
|
|
|
* Registers query vars for API access |
184
|
|
|
* |
185
|
|
|
* @access public |
186
|
|
|
* @since 1.1 |
187
|
|
|
* |
188
|
|
|
* @param array $vars Query vars |
189
|
|
|
* |
190
|
|
|
* @return string[] $vars New query vars |
191
|
|
|
*/ |
192
|
4 |
|
public function query_vars( $vars ) { |
193
|
|
|
|
194
|
4 |
|
$vars[] = 'token'; |
195
|
4 |
|
$vars[] = 'key'; |
196
|
4 |
|
$vars[] = 'query'; |
197
|
4 |
|
$vars[] = 'type'; |
198
|
4 |
|
$vars[] = 'form'; |
199
|
4 |
|
$vars[] = 'number'; |
200
|
4 |
|
$vars[] = 'date'; |
201
|
4 |
|
$vars[] = 'startdate'; |
202
|
4 |
|
$vars[] = 'enddate'; |
203
|
4 |
|
$vars[] = 'donor'; |
204
|
4 |
|
$vars[] = 'format'; |
205
|
4 |
|
$vars[] = 'id'; |
206
|
4 |
|
$vars[] = 'purchasekey'; |
207
|
4 |
|
$vars[] = 'email'; |
208
|
|
|
|
209
|
4 |
|
return $vars; |
210
|
|
|
} |
211
|
|
|
|
212
|
|
|
/** |
213
|
|
|
* Retrieve the API versions |
214
|
|
|
* |
215
|
|
|
* @access public |
216
|
|
|
* @since 1.1 |
217
|
|
|
* @return array |
218
|
|
|
*/ |
219
|
12 |
|
public function get_versions() { |
220
|
12 |
|
return $this->versions; |
221
|
|
|
} |
222
|
|
|
|
223
|
|
|
/** |
224
|
|
|
* Retrieve the API version that was queried |
225
|
|
|
* |
226
|
|
|
* @access public |
227
|
|
|
* @since 1.1 |
228
|
|
|
* @return string |
229
|
|
|
*/ |
230
|
|
|
public function get_queried_version() { |
231
|
|
|
return $this->queried_version; |
232
|
|
|
} |
233
|
|
|
|
234
|
|
|
/** |
235
|
|
|
* Retrieves the default version of the API to use |
236
|
|
|
* |
237
|
|
|
* @access private |
238
|
|
|
* @since 1.1 |
239
|
|
|
* @return string |
240
|
|
|
*/ |
241
|
1 |
|
public function get_default_version() { |
242
|
|
|
|
243
|
1 |
|
$version = get_option( 'give_default_api_version' ); |
244
|
|
|
|
245
|
1 |
|
if ( defined( 'GIVE_API_VERSION' ) ) { |
246
|
1 |
|
$version = GIVE_API_VERSION; |
247
|
1 |
|
} elseif ( ! $version ) { |
248
|
|
|
$version = 'v1'; |
249
|
|
|
} |
250
|
|
|
|
251
|
1 |
|
return $version; |
252
|
|
|
} |
253
|
|
|
|
254
|
|
|
/** |
255
|
|
|
* Sets the version of the API that was queried. |
256
|
|
|
* |
257
|
|
|
* Falls back to the default version if no version is specified |
258
|
|
|
* |
259
|
|
|
* @access private |
260
|
|
|
* @since 1.1 |
261
|
|
|
*/ |
262
|
|
|
private function set_queried_version() { |
263
|
|
|
|
264
|
|
|
global $wp_query; |
|
|
|
|
265
|
|
|
|
266
|
|
|
$version = $wp_query->query_vars['give-api']; |
267
|
|
|
|
268
|
|
|
if ( strpos( $version, '/' ) ) { |
269
|
|
|
|
270
|
|
|
$version = explode( '/', $version ); |
271
|
|
|
$version = strtolower( $version[0] ); |
272
|
|
|
|
273
|
|
|
$wp_query->query_vars['give-api'] = str_replace( $version . '/', '', $wp_query->query_vars['give-api'] ); |
274
|
|
|
|
275
|
|
|
if ( array_key_exists( $version, $this->versions ) ) { |
276
|
|
|
|
277
|
|
|
$this->queried_version = $version; |
278
|
|
|
|
279
|
|
|
} else { |
280
|
|
|
|
281
|
|
|
$this->is_valid_request = false; |
282
|
|
|
$this->invalid_version(); |
283
|
|
|
} |
284
|
|
|
|
285
|
|
|
} else { |
286
|
|
|
|
287
|
|
|
$this->queried_version = $this->get_default_version(); |
288
|
|
|
|
289
|
|
|
} |
290
|
|
|
|
291
|
|
|
} |
292
|
|
|
|
293
|
|
|
/** |
294
|
|
|
* Validate the API request |
295
|
|
|
* |
296
|
|
|
* Checks for the user's public key and token against the secret key |
297
|
|
|
* |
298
|
|
|
* @access private |
299
|
|
|
* @global object $wp_query WordPress Query |
300
|
|
|
* @uses Give_API::get_user() |
301
|
|
|
* @uses Give_API::invalid_key() |
302
|
|
|
* @uses Give_API::invalid_auth() |
303
|
|
|
* @since 1.1 |
304
|
|
|
* @return void |
305
|
|
|
*/ |
306
|
|
|
private function validate_request() { |
307
|
|
|
global $wp_query; |
|
|
|
|
308
|
|
|
|
309
|
|
|
$this->override = false; |
310
|
|
|
|
311
|
|
|
// Make sure we have both user and api key |
312
|
|
|
if ( ! empty( $wp_query->query_vars['give-api'] ) && ( $wp_query->query_vars['give-api'] != 'forms' || ! empty( $wp_query->query_vars['token'] ) ) ) { |
313
|
|
|
|
314
|
|
|
if ( empty( $wp_query->query_vars['token'] ) || empty( $wp_query->query_vars['key'] ) ) { |
315
|
|
|
$this->missing_auth(); |
316
|
|
|
} |
317
|
|
|
|
318
|
|
|
// Retrieve the user by public API key and ensure they exist |
319
|
|
|
if ( ! ( $user = $this->get_user( $wp_query->query_vars['key'] ) ) ) { |
320
|
|
|
|
321
|
|
|
$this->invalid_key(); |
322
|
|
|
|
323
|
|
|
} else { |
324
|
|
|
|
325
|
|
|
$token = urldecode( $wp_query->query_vars['token'] ); |
326
|
|
|
$secret = $this->get_user_secret_key( $user ); |
327
|
|
|
$public = urldecode( $wp_query->query_vars['key'] ); |
328
|
|
|
|
329
|
|
|
if ( hash_equals( md5( $secret . $public ), $token ) ) { |
330
|
|
|
$this->is_valid_request = true; |
331
|
|
|
} else { |
332
|
|
|
$this->invalid_auth(); |
333
|
|
|
} |
334
|
|
|
} |
335
|
|
|
} elseif ( ! empty( $wp_query->query_vars['give-api'] ) && $wp_query->query_vars['give-api'] == 'forms' ) { |
336
|
|
|
$this->is_valid_request = true; |
337
|
|
|
$wp_query->set( 'key', 'public' ); |
338
|
|
|
} |
339
|
|
|
} |
340
|
|
|
|
341
|
|
|
/** |
342
|
|
|
* Retrieve the user ID based on the public key provided |
343
|
|
|
* |
344
|
|
|
* @access public |
345
|
|
|
* @since 1.1 |
346
|
|
|
* @global object $wpdb Used to query the database using the WordPress |
347
|
|
|
* Database API |
348
|
|
|
* |
349
|
|
|
* @param string $key Public Key |
350
|
|
|
* |
351
|
|
|
* @return bool if user ID is found, false otherwise |
352
|
|
|
*/ |
353
|
1 |
|
public function get_user( $key = '' ) { |
354
|
1 |
|
global $wpdb, $wp_query; |
|
|
|
|
355
|
|
|
|
356
|
1 |
|
if ( empty( $key ) ) { |
357
|
|
|
$key = urldecode( $wp_query->query_vars['key'] ); |
358
|
|
|
} |
359
|
|
|
|
360
|
1 |
|
if ( empty( $key ) ) { |
361
|
|
|
return false; |
362
|
|
|
} |
363
|
|
|
|
364
|
1 |
|
$user = get_transient( md5( 'give_api_user_' . $key ) ); |
365
|
|
|
|
366
|
1 |
|
if ( false === $user ) { |
367
|
1 |
|
$user = $wpdb->get_var( $wpdb->prepare( "SELECT user_id FROM $wpdb->usermeta WHERE meta_key = %s LIMIT 1", $key ) ); |
368
|
1 |
|
set_transient( md5( 'give_api_user_' . $key ), $user, DAY_IN_SECONDS ); |
369
|
1 |
|
} |
370
|
|
|
|
371
|
1 |
|
if ( $user != null ) { |
372
|
1 |
|
$this->user_id = $user; |
373
|
|
|
|
374
|
1 |
|
return $user; |
375
|
|
|
} |
376
|
|
|
|
377
|
|
|
return false; |
378
|
|
|
} |
379
|
|
|
|
380
|
2 |
|
public function get_user_public_key( $user_id = 0 ) { |
381
|
2 |
|
global $wpdb; |
|
|
|
|
382
|
|
|
|
383
|
2 |
|
if ( empty( $user_id ) ) { |
384
|
|
|
return ''; |
385
|
|
|
} |
386
|
|
|
|
387
|
2 |
|
$cache_key = md5( 'give_api_user_public_key' . $user_id ); |
388
|
2 |
|
$user_public_key = get_transient( $cache_key ); |
389
|
|
|
|
390
|
2 |
|
if ( empty( $user_public_key ) ) { |
391
|
2 |
|
$user_public_key = $wpdb->get_var( $wpdb->prepare( "SELECT meta_key FROM $wpdb->usermeta WHERE meta_value = 'give_user_public_key' AND user_id = %d", $user_id ) ); |
392
|
2 |
|
set_transient( $cache_key, $user_public_key, HOUR_IN_SECONDS ); |
393
|
2 |
|
} |
394
|
|
|
|
395
|
2 |
|
return $user_public_key; |
396
|
|
|
} |
397
|
|
|
|
398
|
2 |
|
public function get_user_secret_key( $user_id = 0 ) { |
399
|
2 |
|
global $wpdb; |
|
|
|
|
400
|
|
|
|
401
|
2 |
|
if ( empty( $user_id ) ) { |
402
|
|
|
return ''; |
403
|
|
|
} |
404
|
|
|
|
405
|
2 |
|
$cache_key = md5( 'give_api_user_secret_key' . $user_id ); |
406
|
2 |
|
$user_secret_key = get_transient( $cache_key ); |
407
|
|
|
|
408
|
2 |
|
if ( empty( $user_secret_key ) ) { |
409
|
2 |
|
$user_secret_key = $wpdb->get_var( $wpdb->prepare( "SELECT meta_key FROM $wpdb->usermeta WHERE meta_value = 'give_user_secret_key' AND user_id = %d", $user_id ) ); |
410
|
2 |
|
set_transient( $cache_key, $user_secret_key, HOUR_IN_SECONDS ); |
411
|
2 |
|
} |
412
|
|
|
|
413
|
2 |
|
return $user_secret_key; |
414
|
|
|
} |
415
|
|
|
|
416
|
|
|
/** |
417
|
|
|
* Displays a missing authentication error if all the parameters aren't |
418
|
|
|
* provided |
419
|
|
|
* |
420
|
|
|
* @access private |
421
|
|
|
* @uses Give_API::output() |
422
|
|
|
* @since 1.1 |
423
|
|
|
*/ |
424
|
|
|
private function missing_auth() { |
425
|
|
|
$error = array(); |
426
|
|
|
$error['error'] = esc_attr__( 'You must specify both a token and API key!', 'give' ); |
427
|
|
|
|
428
|
|
|
$this->data = $error; |
429
|
|
|
$this->output( 401 ); |
430
|
|
|
} |
431
|
|
|
|
432
|
|
|
/** |
433
|
|
|
* Displays an authentication failed error if the user failed to provide valid |
434
|
|
|
* credentials |
435
|
|
|
* |
436
|
|
|
* @access private |
437
|
|
|
* @since 1.1 |
438
|
|
|
* @uses Give_API::output() |
439
|
|
|
* @return void |
440
|
|
|
*/ |
441
|
|
|
private function invalid_auth() { |
442
|
|
|
$error = array(); |
443
|
|
|
$error['error'] = esc_attr__( 'Your request could not be authenticated!', 'give' ); |
444
|
|
|
|
445
|
|
|
$this->data = $error; |
446
|
|
|
$this->output( 403 ); |
447
|
|
|
} |
448
|
|
|
|
449
|
|
|
/** |
450
|
|
|
* Displays an invalid API key error if the API key provided couldn't be |
451
|
|
|
* validated |
452
|
|
|
* |
453
|
|
|
* @access private |
454
|
|
|
* @since 1.1 |
455
|
|
|
* @uses Give_API::output() |
456
|
|
|
* @return void |
457
|
|
|
*/ |
458
|
|
|
private function invalid_key() { |
459
|
|
|
$error = array(); |
460
|
|
|
$error['error'] = esc_attr__( 'Invalid API key!', 'give' ); |
461
|
|
|
|
462
|
|
|
$this->data = $error; |
463
|
|
|
$this->output( 403 ); |
464
|
|
|
} |
465
|
|
|
|
466
|
|
|
/** |
467
|
|
|
* Displays an invalid version error if the version number passed isn't valid |
468
|
|
|
* |
469
|
|
|
* @access private |
470
|
|
|
* @since 1.1 |
471
|
|
|
* @uses Give_API::output() |
472
|
|
|
* @return void |
473
|
|
|
*/ |
474
|
|
|
private function invalid_version() { |
475
|
|
|
$error = array(); |
476
|
|
|
$error['error'] = esc_attr__( 'Invalid API version!', 'give' ); |
477
|
|
|
|
478
|
|
|
$this->data = $error; |
479
|
|
|
$this->output( 404 ); |
480
|
|
|
} |
481
|
|
|
|
482
|
|
|
/** |
483
|
|
|
* Listens for the API and then processes the API requests |
484
|
|
|
* |
485
|
|
|
* @access public |
486
|
|
|
* @global $wp_query |
487
|
|
|
* @since 1.1 |
488
|
|
|
* @return void |
489
|
|
|
*/ |
490
|
3 |
|
public function process_query() { |
491
|
|
|
|
492
|
3 |
|
global $wp_query; |
|
|
|
|
493
|
|
|
|
494
|
|
|
// Start logging how long the request takes for logging |
495
|
3 |
|
$before = microtime( true ); |
496
|
|
|
|
497
|
|
|
// Check for give-api var. Get out if not present |
498
|
3 |
|
if ( empty( $wp_query->query_vars['give-api'] ) ) { |
499
|
3 |
|
return; |
500
|
|
|
} |
501
|
|
|
|
502
|
|
|
// Determine which version was queried |
503
|
|
|
$this->set_queried_version(); |
504
|
|
|
|
505
|
|
|
// Determine the kind of query |
506
|
|
|
$this->set_query_mode(); |
507
|
|
|
|
508
|
|
|
// Check for a valid user and set errors if necessary |
509
|
|
|
$this->validate_request(); |
510
|
|
|
|
511
|
|
|
// Only proceed if no errors have been noted |
512
|
|
|
if ( ! $this->is_valid_request ) { |
513
|
|
|
return; |
514
|
|
|
} |
515
|
|
|
|
516
|
|
|
if ( ! defined( 'GIVE_DOING_API' ) ) { |
517
|
|
|
define( 'GIVE_DOING_API', true ); |
518
|
|
|
} |
519
|
|
|
|
520
|
|
|
$data = array(); |
521
|
|
|
$this->routes = new $this->versions[$this->get_queried_version()]; |
522
|
|
|
$this->routes->validate_request(); |
523
|
|
|
|
524
|
|
|
switch ( $this->endpoint ) : |
525
|
|
|
|
526
|
|
|
case 'stats' : |
527
|
|
|
|
528
|
|
|
$data = $this->routes->get_stats( array( |
529
|
|
|
'type' => isset( $wp_query->query_vars['type'] ) ? $wp_query->query_vars['type'] : null, |
530
|
|
|
'form' => isset( $wp_query->query_vars['form'] ) ? $wp_query->query_vars['form'] : null, |
531
|
|
|
'date' => isset( $wp_query->query_vars['date'] ) ? $wp_query->query_vars['date'] : null, |
532
|
|
|
'startdate' => isset( $wp_query->query_vars['startdate'] ) ? $wp_query->query_vars['startdate'] : null, |
533
|
|
|
'enddate' => isset( $wp_query->query_vars['enddate'] ) ? $wp_query->query_vars['enddate'] : null |
534
|
|
|
) ); |
535
|
|
|
|
536
|
|
|
break; |
537
|
|
|
|
538
|
|
|
case 'forms' : |
539
|
|
|
|
540
|
|
|
$form = isset( $wp_query->query_vars['form'] ) ? $wp_query->query_vars['form'] : null; |
541
|
|
|
|
542
|
|
|
$data = $this->routes->get_forms( $form ); |
543
|
|
|
|
544
|
|
|
break; |
545
|
|
|
|
546
|
|
|
case 'donors' : |
547
|
|
|
|
548
|
|
|
$customer = isset( $wp_query->query_vars['donor'] ) ? $wp_query->query_vars['donor'] : null; |
549
|
|
|
|
550
|
|
|
$data = $this->routes->get_customers( $customer ); |
551
|
|
|
|
552
|
|
|
break; |
553
|
|
|
|
554
|
|
|
case 'donations' : |
555
|
|
|
|
556
|
|
|
$data = $this->routes->get_recent_donations(); |
557
|
|
|
|
558
|
|
|
break; |
559
|
|
|
|
560
|
|
|
endswitch; |
561
|
|
|
|
562
|
|
|
// Allow extensions to setup their own return data |
563
|
|
|
$this->data = apply_filters( 'give_api_output_data', $data, $this->endpoint, $this ); |
564
|
|
|
|
565
|
|
|
$after = microtime( true ); |
566
|
|
|
$request_time = ( $after - $before ); |
567
|
|
|
$this->data['request_speed'] = $request_time; |
568
|
|
|
|
569
|
|
|
// Log this API request, if enabled. We log it here because we have access to errors. |
570
|
|
|
$this->log_request( $this->data ); |
571
|
|
|
|
572
|
|
|
// Send out data to the output function |
573
|
|
|
$this->output(); |
574
|
|
|
} |
575
|
|
|
|
576
|
|
|
/** |
577
|
|
|
* Returns the API endpoint requested |
578
|
|
|
* |
579
|
|
|
* @access private |
580
|
|
|
* @since 1.1 |
581
|
|
|
* @return string $query Query mode |
582
|
|
|
*/ |
583
|
|
|
public function get_query_mode() { |
584
|
|
|
|
585
|
|
|
return $this->endpoint; |
586
|
|
|
} |
587
|
|
|
|
588
|
|
|
/** |
589
|
|
|
* Determines the kind of query requested and also ensure it is a valid query |
590
|
|
|
* |
591
|
|
|
* @access private |
592
|
|
|
* @since 1.1 |
593
|
|
|
* @global $wp_query |
594
|
|
|
*/ |
595
|
|
|
public function set_query_mode() { |
596
|
|
|
|
597
|
|
|
global $wp_query; |
|
|
|
|
598
|
|
|
|
599
|
|
|
// Whitelist our query options |
600
|
|
|
$accepted = apply_filters( 'give_api_valid_query_modes', array( |
601
|
|
|
'stats', |
602
|
|
|
'forms', |
603
|
|
|
'donors', |
604
|
|
|
'donations' |
605
|
|
|
) ); |
606
|
|
|
|
607
|
|
|
$query = isset( $wp_query->query_vars['give-api'] ) ? $wp_query->query_vars['give-api'] : null; |
608
|
|
|
$query = str_replace( $this->queried_version . '/', '', $query ); |
609
|
|
|
|
610
|
|
|
$error = array(); |
611
|
|
|
|
612
|
|
|
// Make sure our query is valid |
613
|
|
|
if ( ! in_array( $query, $accepted ) ) { |
614
|
|
|
$error['error'] = __( 'Invalid query!', 'give' ); |
615
|
|
|
|
616
|
|
|
$this->data = $error; |
617
|
|
|
$this->output(); |
618
|
|
|
} |
619
|
|
|
|
620
|
|
|
$this->endpoint = $query; |
621
|
|
|
} |
622
|
|
|
|
623
|
|
|
/** |
624
|
|
|
* Get page number |
625
|
|
|
* |
626
|
|
|
* @access private |
627
|
|
|
* @since 1.1 |
628
|
|
|
* @global $wp_query |
629
|
|
|
* @return int $wp_query->query_vars['page'] if page number returned (default: 1) |
630
|
|
|
*/ |
631
|
10 |
|
public function get_paged() { |
632
|
10 |
|
global $wp_query; |
|
|
|
|
633
|
|
|
|
634
|
10 |
|
return isset( $wp_query->query_vars['page'] ) ? $wp_query->query_vars['page'] : 1; |
635
|
|
|
} |
636
|
|
|
|
637
|
|
|
|
638
|
|
|
/** |
639
|
|
|
* Number of results to display per page |
640
|
|
|
* |
641
|
|
|
* @access private |
642
|
|
|
* @since 1.1 |
643
|
|
|
* @global $wp_query |
644
|
|
|
* @return int $per_page Results to display per page (default: 10) |
645
|
|
|
*/ |
646
|
10 |
|
public function per_page() { |
647
|
10 |
|
global $wp_query; |
|
|
|
|
648
|
|
|
|
649
|
10 |
|
$per_page = isset( $wp_query->query_vars['number'] ) ? $wp_query->query_vars['number'] : 10; |
650
|
|
|
|
651
|
10 |
|
if ( $per_page < 0 && $this->get_query_mode() == 'donors' ) { |
652
|
|
|
$per_page = 99999999; |
653
|
|
|
} // Customers query doesn't support -1 |
654
|
|
|
|
655
|
10 |
|
return apply_filters( 'give_api_results_per_page', $per_page ); |
656
|
|
|
} |
657
|
|
|
|
658
|
|
|
/** |
659
|
|
|
* Sets up the dates used to retrieve earnings/donations |
660
|
|
|
* |
661
|
|
|
* @access public |
662
|
|
|
* @since 1.2 |
663
|
|
|
* |
664
|
|
|
* @param array $args Arguments to override defaults |
665
|
|
|
* |
666
|
|
|
* @return array $dates |
667
|
|
|
*/ |
668
|
|
|
public function get_dates( $args = array() ) { |
669
|
|
|
$dates = array(); |
670
|
|
|
|
671
|
|
|
$defaults = array( |
672
|
|
|
'type' => '', |
673
|
|
|
'form' => null, |
674
|
|
|
'date' => null, |
675
|
|
|
'startdate' => null, |
676
|
|
|
'enddate' => null |
677
|
|
|
); |
678
|
|
|
|
679
|
|
|
$args = wp_parse_args( $args, $defaults ); |
680
|
|
|
|
681
|
|
|
$current_time = current_time( 'timestamp' ); |
682
|
|
|
|
683
|
|
|
if ( 'range' === $args['date'] ) { |
684
|
|
|
$startdate = strtotime( $args['startdate'] ); |
685
|
|
|
$enddate = strtotime( $args['enddate'] ); |
686
|
|
|
$dates['day_start'] = date( 'd', $startdate ); |
687
|
|
|
$dates['day_end'] = date( 'd', $enddate ); |
688
|
|
|
$dates['m_start'] = date( 'n', $startdate ); |
689
|
|
|
$dates['m_end'] = date( 'n', $enddate ); |
690
|
|
|
$dates['year'] = date( 'Y', $startdate ); |
691
|
|
|
$dates['year_end'] = date( 'Y', $enddate ); |
692
|
|
|
} else { |
693
|
|
|
// Modify dates based on predefined ranges |
694
|
|
|
switch ( $args['date'] ) : |
695
|
|
|
|
696
|
|
|
case 'this_month' : |
697
|
|
|
$dates['day'] = null; |
698
|
|
|
$dates['m_start'] = date( 'n', $current_time ); |
699
|
|
|
$dates['m_end'] = date( 'n', $current_time ); |
700
|
|
|
$dates['year'] = date( 'Y', $current_time ); |
701
|
|
|
break; |
702
|
|
|
|
703
|
|
|
case 'last_month' : |
704
|
|
|
$dates['day'] = null; |
705
|
|
|
$dates['m_start'] = date( 'n', $current_time ) == 1 ? 12 : date( 'n', $current_time ) - 1; |
706
|
|
|
$dates['m_end'] = $dates['m_start']; |
707
|
|
|
$dates['year'] = date( 'n', $current_time ) == 1 ? date( 'Y', $current_time ) - 1 : date( 'Y', $current_time ); |
708
|
|
|
break; |
709
|
|
|
|
710
|
|
|
case 'today' : |
711
|
|
|
$dates['day'] = date( 'd', $current_time ); |
712
|
|
|
$dates['m_start'] = date( 'n', $current_time ); |
713
|
|
|
$dates['m_end'] = date( 'n', $current_time ); |
714
|
|
|
$dates['year'] = date( 'Y', $current_time ); |
715
|
|
|
break; |
716
|
|
|
|
717
|
|
|
case 'yesterday' : |
718
|
|
|
|
719
|
|
|
$year = date( 'Y', $current_time ); |
720
|
|
|
$month = date( 'n', $current_time ); |
721
|
|
|
$day = date( 'd', $current_time ); |
722
|
|
|
|
723
|
|
|
if ( $month == 1 && $day == 1 ) { |
724
|
|
|
|
725
|
|
|
$year -= 1; |
726
|
|
|
$month = 12; |
727
|
|
|
$day = cal_days_in_month( CAL_GREGORIAN, $month, $year ); |
728
|
|
|
|
729
|
|
|
} elseif ( $month > 1 && $day == 1 ) { |
730
|
|
|
|
731
|
|
|
$month -= 1; |
732
|
|
|
$day = cal_days_in_month( CAL_GREGORIAN, $month, $year ); |
733
|
|
|
|
734
|
|
|
} else { |
735
|
|
|
|
736
|
|
|
$day -= 1; |
737
|
|
|
|
738
|
|
|
} |
739
|
|
|
|
740
|
|
|
$dates['day'] = $day; |
741
|
|
|
$dates['m_start'] = $month; |
742
|
|
|
$dates['m_end'] = $month; |
743
|
|
|
$dates['year'] = $year; |
744
|
|
|
|
745
|
|
|
break; |
746
|
|
|
|
747
|
|
|
case 'this_quarter' : |
748
|
|
|
$month_now = date( 'n', $current_time ); |
749
|
|
|
|
750
|
|
|
$dates['day'] = null; |
751
|
|
|
|
752
|
|
|
if ( $month_now <= 3 ) { |
753
|
|
|
|
754
|
|
|
$dates['m_start'] = 1; |
755
|
|
|
$dates['m_end'] = 3; |
756
|
|
|
$dates['year'] = date( 'Y', $current_time ); |
757
|
|
|
|
758
|
|
|
} else if ( $month_now <= 6 ) { |
759
|
|
|
|
760
|
|
|
$dates['m_start'] = 4; |
761
|
|
|
$dates['m_end'] = 6; |
762
|
|
|
$dates['year'] = date( 'Y', $current_time ); |
763
|
|
|
|
764
|
|
|
} else if ( $month_now <= 9 ) { |
765
|
|
|
|
766
|
|
|
$dates['m_start'] = 7; |
767
|
|
|
$dates['m_end'] = 9; |
768
|
|
|
$dates['year'] = date( 'Y', $current_time ); |
769
|
|
|
|
770
|
|
|
} else { |
771
|
|
|
|
772
|
|
|
$dates['m_start'] = 10; |
773
|
|
|
$dates['m_end'] = 12; |
774
|
|
|
$dates['year'] = date( 'Y', $current_time ); |
775
|
|
|
|
776
|
|
|
} |
777
|
|
|
break; |
778
|
|
|
|
779
|
|
|
case 'last_quarter' : |
780
|
|
|
$month_now = date( 'n', $current_time ); |
781
|
|
|
|
782
|
|
|
$dates['day'] = null; |
783
|
|
|
|
784
|
|
|
if ( $month_now <= 3 ) { |
785
|
|
|
|
786
|
|
|
$dates['m_start'] = 10; |
787
|
|
|
$dates['m_end'] = 12; |
788
|
|
|
$dates['year'] = date( 'Y', $current_time ) - 1; // Previous year |
789
|
|
|
|
790
|
|
|
} else if ( $month_now <= 6 ) { |
791
|
|
|
|
792
|
|
|
$dates['m_start'] = 1; |
793
|
|
|
$dates['m_end'] = 3; |
794
|
|
|
$dates['year'] = date( 'Y', $current_time ); |
795
|
|
|
|
796
|
|
|
} else if ( $month_now <= 9 ) { |
797
|
|
|
|
798
|
|
|
$dates['m_start'] = 4; |
799
|
|
|
$dates['m_end'] = 6; |
800
|
|
|
$dates['year'] = date( 'Y', $current_time ); |
801
|
|
|
|
802
|
|
|
} else { |
803
|
|
|
|
804
|
|
|
$dates['m_start'] = 7; |
805
|
|
|
$dates['m_end'] = 9; |
806
|
|
|
$dates['year'] = date( 'Y', $current_time ); |
807
|
|
|
|
808
|
|
|
} |
809
|
|
|
break; |
810
|
|
|
|
811
|
|
|
case 'this_year' : |
812
|
|
|
$dates['day'] = null; |
813
|
|
|
$dates['m_start'] = null; |
814
|
|
|
$dates['m_end'] = null; |
815
|
|
|
$dates['year'] = date( 'Y', $current_time ); |
816
|
|
|
break; |
817
|
|
|
|
818
|
|
|
case 'last_year' : |
819
|
|
|
$dates['day'] = null; |
820
|
|
|
$dates['m_start'] = null; |
821
|
|
|
$dates['m_end'] = null; |
822
|
|
|
$dates['year'] = date( 'Y', $current_time ) - 1; |
823
|
|
|
break; |
824
|
|
|
|
825
|
|
|
endswitch; |
826
|
|
|
} |
827
|
|
|
|
828
|
|
|
/** |
829
|
|
|
* Returns the filters for the dates used to retreive earnings/donations |
830
|
|
|
* |
831
|
|
|
* @since 1.2 |
832
|
|
|
* |
833
|
|
|
* @param object $dates The dates used for retreiving earnings/donations |
834
|
|
|
*/ |
835
|
|
|
|
836
|
|
|
return apply_filters( 'give_api_stat_dates', $dates ); |
837
|
|
|
} |
838
|
|
|
|
839
|
|
|
/** |
840
|
|
|
* Process Get Customers API Request |
841
|
|
|
* |
842
|
|
|
* @access public |
843
|
|
|
* @since 1.1 |
844
|
|
|
* @global object $wpdb Used to query the database using the WordPress |
845
|
|
|
* Database API |
846
|
|
|
* |
847
|
|
|
* @param int $customer Customer ID |
848
|
|
|
* |
849
|
|
|
* @return array $customers Multidimensional array of the customers |
850
|
|
|
*/ |
851
|
1 |
|
public function get_customers( $customer = null ) { |
852
|
|
|
|
853
|
1 |
|
$customers = array(); |
854
|
1 |
|
$error = array(); |
855
|
1 |
|
if ( ! user_can( $this->user_id, 'view_give_sensitive_data' ) && ! $this->override ) { |
856
|
|
|
return $customers; |
857
|
|
|
} |
858
|
|
|
|
859
|
1 |
|
global $wpdb; |
|
|
|
|
860
|
|
|
|
861
|
1 |
|
$paged = $this->get_paged(); |
862
|
1 |
|
$per_page = $this->per_page(); |
863
|
1 |
|
$offset = $per_page * ( $paged - 1 ); |
864
|
|
|
|
865
|
1 |
|
if ( is_numeric( $customer ) ) { |
866
|
|
|
$field = 'id'; |
867
|
|
|
} else { |
868
|
1 |
|
$field = 'email'; |
869
|
|
|
} |
870
|
|
|
|
871
|
1 |
|
$customer_query = Give()->customers->get_customers( array( |
|
|
|
|
872
|
1 |
|
'number' => $per_page, |
873
|
1 |
|
'offset' => $offset, |
874
|
|
|
$field => $customer |
875
|
1 |
|
) ); |
876
|
1 |
|
$customer_count = 0; |
877
|
|
|
|
878
|
1 |
|
if ( $customer_query ) { |
879
|
|
|
|
880
|
1 |
|
foreach ( $customer_query as $customer_obj ) { |
881
|
|
|
|
882
|
1 |
|
$names = explode( ' ', $customer_obj->name ); |
883
|
1 |
|
$first_name = ! empty( $names[0] ) ? $names[0] : ''; |
884
|
1 |
|
$last_name = ''; |
885
|
1 |
|
if ( ! empty( $names[1] ) ) { |
886
|
|
|
unset( $names[0] ); |
887
|
|
|
$last_name = implode( ' ', $names ); |
888
|
|
|
} |
889
|
|
|
|
890
|
1 |
|
$customers['donors'][ $customer_count ]['info']['user_id'] = ''; |
891
|
1 |
|
$customers['donors'][ $customer_count ]['info']['username'] = ''; |
892
|
1 |
|
$customers['donors'][ $customer_count ]['info']['display_name'] = ''; |
893
|
1 |
|
$customers['donors'][ $customer_count ]['info']['customer_id'] = $customer_obj->id; |
894
|
1 |
|
$customers['donors'][ $customer_count ]['info']['first_name'] = $first_name; |
895
|
1 |
|
$customers['donors'][ $customer_count ]['info']['last_name'] = $last_name; |
896
|
1 |
|
$customers['donors'][ $customer_count ]['info']['email'] = $customer_obj->email; |
897
|
|
|
|
898
|
1 |
|
if ( ! empty( $customer_obj->user_id ) ) { |
899
|
|
|
|
900
|
1 |
|
$user_data = get_userdata( $customer_obj->user_id ); |
901
|
|
|
|
902
|
|
|
// Customer with registered account |
903
|
1 |
|
$customers['donors'][ $customer_count ]['info']['user_id'] = $customer_obj->user_id; |
904
|
1 |
|
$customers['donors'][ $customer_count ]['info']['username'] = $user_data->user_login; |
905
|
1 |
|
$customers['donors'][ $customer_count ]['info']['display_name'] = $user_data->display_name; |
906
|
|
|
|
907
|
1 |
|
} |
908
|
|
|
|
909
|
1 |
|
$customers['donors'][ $customer_count ]['stats']['total_donations'] = $customer_obj->purchase_count; |
910
|
1 |
|
$customers['donors'][ $customer_count ]['stats']['total_spent'] = $customer_obj->purchase_value; |
911
|
|
|
|
912
|
1 |
|
$customer_count ++; |
913
|
|
|
|
914
|
1 |
|
} |
915
|
|
|
|
916
|
1 |
|
} elseif ( $customer ) { |
917
|
|
|
|
918
|
|
|
$error['error'] = sprintf( __( 'Donor %s not found!', 'give' ), $customer ); |
919
|
|
|
|
920
|
|
|
return $error; |
921
|
|
|
|
922
|
|
|
} else { |
923
|
|
|
|
924
|
|
|
$error['error'] = __( 'No donors found!', 'give' ); |
925
|
|
|
|
926
|
|
|
return $error; |
927
|
|
|
|
928
|
|
|
} |
929
|
|
|
|
930
|
1 |
|
return $customers; |
931
|
|
|
} |
932
|
|
|
|
933
|
|
|
/** |
934
|
|
|
* Process Get Products API Request |
935
|
|
|
* |
936
|
|
|
* @access public |
937
|
|
|
* @since 1.1 |
938
|
|
|
* |
939
|
|
|
* @param int $form Give Form ID |
940
|
|
|
* |
941
|
|
|
* @return array $customers Multidimensional array of the forms |
942
|
|
|
*/ |
943
|
10 |
|
public function get_forms( $form = null ) { |
944
|
|
|
|
945
|
10 |
|
$forms = array(); |
946
|
10 |
|
$error = array(); |
947
|
|
|
|
948
|
10 |
|
if ( $form == null ) { |
|
|
|
|
949
|
10 |
|
$forms['forms'] = array(); |
950
|
|
|
|
951
|
10 |
|
$form_list = get_posts( array( |
952
|
10 |
|
'post_type' => 'give_forms', |
953
|
10 |
|
'posts_per_page' => $this->per_page(), |
954
|
10 |
|
'suppress_filters' => true, |
955
|
10 |
|
'paged' => $this->get_paged() |
956
|
10 |
|
) ); |
957
|
|
|
|
958
|
10 |
|
if ( $form_list ) { |
959
|
10 |
|
$i = 0; |
960
|
10 |
|
foreach ( $form_list as $form_info ) { |
961
|
10 |
|
$forms['forms'][ $i ] = $this->get_form_data( $form_info ); |
962
|
10 |
|
$i ++; |
963
|
10 |
|
} |
964
|
10 |
|
} |
965
|
10 |
|
} else { |
966
|
|
|
if ( get_post_type( $form ) == 'give_forms' ) { |
967
|
|
|
$form_info = get_post( $form ); |
968
|
|
|
|
969
|
|
|
$forms['forms'][0] = $this->get_form_data( $form_info ); |
970
|
|
|
|
971
|
|
|
} else { |
972
|
|
|
$error['error'] = sprintf( __( 'Form %s not found!', 'give' ), $form ); |
973
|
|
|
|
974
|
|
|
return $error; |
975
|
|
|
} |
976
|
|
|
} |
977
|
|
|
|
978
|
10 |
|
return $forms; |
979
|
|
|
} |
980
|
|
|
|
981
|
|
|
/** |
982
|
|
|
* Given a give_forms post object, generate the data for the API output |
983
|
|
|
* |
984
|
|
|
* @since 1.1 |
985
|
|
|
* |
986
|
|
|
* @param object $form_info The Download Post Object |
987
|
|
|
* |
988
|
|
|
* @return array Array of post data to return back in the API |
989
|
|
|
*/ |
990
|
10 |
|
private function get_form_data( $form_info ) { |
991
|
|
|
|
992
|
10 |
|
$form = array(); |
993
|
|
|
|
994
|
10 |
|
$form['info']['id'] = $form_info->ID; |
995
|
10 |
|
$form['info']['slug'] = $form_info->post_name; |
996
|
10 |
|
$form['info']['title'] = $form_info->post_title; |
997
|
10 |
|
$form['info']['create_date'] = $form_info->post_date; |
998
|
10 |
|
$form['info']['modified_date'] = $form_info->post_modified; |
999
|
10 |
|
$form['info']['status'] = $form_info->post_status; |
1000
|
10 |
|
$form['info']['link'] = html_entity_decode( $form_info->guid ); |
1001
|
10 |
|
$form['info']['content'] = get_post_meta( $form_info->ID, '_give_form_content', true ); |
1002
|
10 |
|
$form['info']['thumbnail'] = wp_get_attachment_url( get_post_thumbnail_id( $form_info->ID ) ); |
1003
|
|
|
|
1004
|
10 |
|
if ( give_get_option( 'enable_categories' ) == 'on' ) { |
1005
|
|
|
$form['info']['category'] = get_the_terms( $form_info, 'give_forms_category' ); |
1006
|
|
|
$form['info']['tags'] = get_the_terms( $form_info, 'give_forms_tag' ); |
1007
|
|
|
} |
1008
|
10 |
|
if ( give_get_option( 'enable_tags' ) == 'on' ) { |
1009
|
|
|
$form['info']['tags'] = get_the_terms( $form_info, 'give_forms_tag' ); |
1010
|
|
|
} |
1011
|
|
|
|
1012
|
10 |
|
if ( user_can( $this->user_id, 'view_give_reports' ) || $this->override ) { |
1013
|
10 |
|
$form['stats']['total']['donations'] = give_get_form_sales_stats( $form_info->ID ); |
1014
|
10 |
|
$form['stats']['total']['earnings'] = give_get_form_earnings_stats( $form_info->ID ); |
1015
|
10 |
|
$form['stats']['monthly_average']['donations'] = give_get_average_monthly_form_sales( $form_info->ID ); |
1016
|
10 |
|
$form['stats']['monthly_average']['earnings'] = give_get_average_monthly_form_earnings( $form_info->ID ); |
1017
|
10 |
|
} |
1018
|
|
|
|
1019
|
10 |
|
$counter = 0; |
1020
|
10 |
|
if ( give_has_variable_prices( $form_info->ID ) ) { |
1021
|
10 |
|
foreach ( give_get_variable_prices( $form_info->ID ) as $price ) { |
1022
|
10 |
|
$counter ++; |
1023
|
|
|
//muli-level item |
1024
|
10 |
|
$level = isset( $price['_give_text'] ) ? $price['_give_text'] : 'level-' . $counter; |
1025
|
10 |
|
$form['pricing'][ sanitize_key( $level ) ] = $price['_give_amount']; |
1026
|
|
|
|
1027
|
10 |
|
} |
1028
|
10 |
|
} else { |
1029
|
|
|
$form['pricing']['amount'] = give_get_form_price( $form_info->ID ); |
1030
|
|
|
} |
1031
|
|
|
|
1032
|
10 |
|
if ( user_can( $this->user_id, 'view_give_sensitive_data' ) || $this->override ) { |
1033
|
|
|
|
1034
|
|
|
//Sensitive data here |
1035
|
10 |
|
do_action( 'give_api_sensitive_data' ); |
1036
|
|
|
|
1037
|
10 |
|
} |
1038
|
|
|
|
1039
|
10 |
|
return apply_filters( 'give_api_forms_form', $form ); |
1040
|
|
|
|
1041
|
|
|
} |
1042
|
|
|
|
1043
|
|
|
/** |
1044
|
|
|
* Process Get Stats API Request |
1045
|
|
|
* |
1046
|
|
|
* @since 1.1 |
1047
|
|
|
* |
1048
|
|
|
* @global object $wpdb Used to query the database using the WordPress |
1049
|
|
|
* |
1050
|
|
|
* @param array $args Arguments provided by API Request |
1051
|
|
|
* |
1052
|
|
|
* @return array |
1053
|
|
|
*/ |
1054
|
|
|
public function get_stats( $args = array() ) { |
1055
|
|
|
$defaults = array( |
1056
|
|
|
'type' => null, |
1057
|
|
|
'form' => null, |
1058
|
|
|
'date' => null, |
1059
|
|
|
'startdate' => null, |
1060
|
|
|
'enddate' => null |
1061
|
|
|
); |
1062
|
|
|
|
1063
|
|
|
$args = wp_parse_args( $args, $defaults ); |
1064
|
|
|
|
1065
|
|
|
$dates = $this->get_dates( $args ); |
1066
|
|
|
|
1067
|
|
|
$stats = array(); |
1068
|
|
|
$earnings = array( |
1069
|
|
|
'earnings' => array() |
1070
|
|
|
); |
1071
|
|
|
$sales = array( |
1072
|
|
|
'donations' => array() |
1073
|
|
|
); |
1074
|
|
|
$error = array(); |
1075
|
|
|
|
1076
|
|
|
if ( ! user_can( $this->user_id, 'view_give_reports' ) && ! $this->override ) { |
1077
|
|
|
return $stats; |
1078
|
|
|
} |
1079
|
|
|
|
1080
|
|
|
if ( $args['type'] == 'donations' ) { |
1081
|
|
|
|
1082
|
|
|
if ( $args['form'] == null ) { |
1083
|
|
|
if ( $args['date'] == null ) { |
1084
|
|
|
$sales = $this->get_default_sales_stats(); |
1085
|
|
|
} elseif ( $args['date'] === 'range' ) { |
1086
|
|
|
// Return sales for a date range |
1087
|
|
|
|
1088
|
|
|
// Ensure the end date is later than the start date |
1089
|
|
|
if ( $args['enddate'] < $args['startdate'] ) { |
1090
|
|
|
$error['error'] = __( 'The end date must be later than the start date!', 'give' ); |
1091
|
|
|
} |
1092
|
|
|
|
1093
|
|
|
// Ensure both the start and end date are specified |
1094
|
|
|
if ( empty( $args['startdate'] ) || empty( $args['enddate'] ) ) { |
1095
|
|
|
$error['error'] = __( 'Invalid or no date range specified!', 'give' ); |
1096
|
|
|
} |
1097
|
|
|
|
1098
|
|
|
$total = 0; |
1099
|
|
|
|
1100
|
|
|
// Loop through the years |
1101
|
|
|
$y = $dates['year']; |
1102
|
|
|
while ( $y <= $dates['year_end'] ) : |
1103
|
|
|
|
1104
|
|
|
if ( $dates['year'] == $dates['year_end'] ) { |
1105
|
|
|
$month_start = $dates['m_start']; |
1106
|
|
|
$month_end = $dates['m_end']; |
1107
|
|
|
} elseif ( $y == $dates['year'] && $dates['year_end'] > $dates['year'] ) { |
1108
|
|
|
$month_start = $dates['m_start']; |
1109
|
|
|
$month_end = 12; |
1110
|
|
|
} elseif ( $y == $dates['year_end'] ) { |
1111
|
|
|
$month_start = 1; |
1112
|
|
|
$month_end = $dates['m_end']; |
1113
|
|
|
} else { |
1114
|
|
|
$month_start = 1; |
1115
|
|
|
$month_end = 12; |
1116
|
|
|
} |
1117
|
|
|
|
1118
|
|
|
$i = $month_start; |
1119
|
|
|
while ( $i <= $month_end ) : |
1120
|
|
|
|
1121
|
|
|
if ( $i == $dates['m_start'] ) { |
1122
|
|
|
$d = $dates['day_start']; |
1123
|
|
|
} else { |
1124
|
|
|
$d = 1; |
1125
|
|
|
} |
1126
|
|
|
|
1127
|
|
|
if ( $i == $dates['m_end'] ) { |
1128
|
|
|
$num_of_days = $dates['day_end']; |
1129
|
|
|
} else { |
1130
|
|
|
$num_of_days = cal_days_in_month( CAL_GREGORIAN, $i, $y ); |
1131
|
|
|
} |
1132
|
|
|
|
1133
|
|
|
while ( $d <= $num_of_days ) : |
1134
|
|
|
$sale_count = give_get_sales_by_date( $d, $i, $y ); |
1135
|
|
|
$date_key = date( 'Ymd', strtotime( $y . '/' . $i . '/' . $d ) ); |
1136
|
|
|
if ( ! isset( $sales['sales'][ $date_key ] ) ) { |
1137
|
|
|
$sales['sales'][ $date_key ] = 0; |
1138
|
|
|
} |
1139
|
|
|
$sales['sales'][ $date_key ] += $sale_count; |
1140
|
|
|
$total += $sale_count; |
1141
|
|
|
$d ++; |
1142
|
|
|
endwhile; |
1143
|
|
|
$i ++; |
1144
|
|
|
endwhile; |
1145
|
|
|
|
1146
|
|
|
$y ++; |
1147
|
|
|
endwhile; |
1148
|
|
|
|
1149
|
|
|
$sales['totals'] = $total; |
1150
|
|
|
} else { |
1151
|
|
|
if ( $args['date'] == 'this_quarter' || $args['date'] == 'last_quarter' ) { |
1152
|
|
|
$sales_count = 0; |
1153
|
|
|
|
1154
|
|
|
// Loop through the months |
1155
|
|
|
$month = $dates['m_start']; |
1156
|
|
|
|
1157
|
|
|
while ( $month <= $dates['m_end'] ) : |
1158
|
|
|
$sales_count += give_get_sales_by_date( null, $month, $dates['year'] ); |
1159
|
|
|
$month ++; |
1160
|
|
|
endwhile; |
1161
|
|
|
|
1162
|
|
|
$sales['donations'][ $args['date'] ] = $sales_count; |
1163
|
|
|
} else { |
1164
|
|
|
$sales['donations'][ $args['date'] ] = give_get_sales_by_date( $dates['day'], $dates['m_start'], $dates['year'] ); |
1165
|
|
|
} |
1166
|
|
|
} |
1167
|
|
|
} elseif ( $args['form'] == 'all' ) { |
1168
|
|
|
$forms = get_posts( array( 'post_type' => 'give_forms', 'nopaging' => true ) ); |
1169
|
|
|
$i = 0; |
1170
|
|
|
foreach ( $forms as $form_info ) { |
1171
|
|
|
$sales['donations'][ $i ] = array( $form_info->post_name => give_get_form_sales_stats( $form_info->ID ) ); |
1172
|
|
|
$i ++; |
1173
|
|
|
} |
1174
|
|
|
} else { |
1175
|
|
|
if ( get_post_type( $args['form'] ) == 'give_forms' ) { |
1176
|
|
|
$form_info = get_post( $args['form'] ); |
1177
|
|
|
$sales['donations'][0] = array( $form_info->post_name => give_get_form_sales_stats( $args['form'] ) ); |
1178
|
|
|
} else { |
1179
|
|
|
$error['error'] = sprintf( __( 'Product %s not found!', 'give' ), $args['form'] ); |
1180
|
|
|
} |
1181
|
|
|
} |
1182
|
|
|
|
1183
|
|
|
if ( ! empty( $error ) ) { |
1184
|
|
|
return $error; |
1185
|
|
|
} |
1186
|
|
|
|
1187
|
|
|
return $sales; |
1188
|
|
|
|
1189
|
|
|
} elseif ( $args['type'] == 'earnings' ) { |
1190
|
|
|
if ( $args['form'] == null ) { |
1191
|
|
|
if ( $args['date'] == null ) { |
1192
|
|
|
$earnings = $this->get_default_earnings_stats(); |
1193
|
|
|
} elseif ( $args['date'] === 'range' ) { |
1194
|
|
|
// Return sales for a date range |
1195
|
|
|
|
1196
|
|
|
// Ensure the end date is later than the start date |
1197
|
|
|
if ( $args['enddate'] < $args['startdate'] ) { |
1198
|
|
|
$error['error'] = __( 'The end date must be later than the start date!', 'give' ); |
1199
|
|
|
} |
1200
|
|
|
|
1201
|
|
|
// Ensure both the start and end date are specified |
1202
|
|
|
if ( empty( $args['startdate'] ) || empty( $args['enddate'] ) ) { |
1203
|
|
|
$error['error'] = __( 'Invalid or no date range specified!', 'give' ); |
1204
|
|
|
} |
1205
|
|
|
|
1206
|
|
|
$total = (float) 0.00; |
1207
|
|
|
|
1208
|
|
|
// Loop through the years |
1209
|
|
|
$y = $dates['year']; |
1210
|
|
|
if ( ! isset( $earnings['earnings'] ) ) { |
1211
|
|
|
$earnings['earnings'] = array(); |
1212
|
|
|
} |
1213
|
|
|
while ( $y <= $dates['year_end'] ) : |
1214
|
|
|
|
1215
|
|
|
if ( $dates['year'] == $dates['year_end'] ) { |
1216
|
|
|
$month_start = $dates['m_start']; |
1217
|
|
|
$month_end = $dates['m_end']; |
1218
|
|
|
} elseif ( $y == $dates['year'] && $dates['year_end'] > $dates['year'] ) { |
1219
|
|
|
$month_start = $dates['m_start']; |
1220
|
|
|
$month_end = 12; |
1221
|
|
|
} elseif ( $y == $dates['year_end'] ) { |
1222
|
|
|
$month_start = 1; |
1223
|
|
|
$month_end = $dates['m_end']; |
1224
|
|
|
} else { |
1225
|
|
|
$month_start = 1; |
1226
|
|
|
$month_end = 12; |
1227
|
|
|
} |
1228
|
|
|
|
1229
|
|
|
$i = $month_start; |
1230
|
|
|
while ( $i <= $month_end ) : |
1231
|
|
|
|
1232
|
|
|
if ( $i == $dates['m_start'] ) { |
1233
|
|
|
$d = $dates['day_start']; |
1234
|
|
|
} else { |
1235
|
|
|
$d = 1; |
1236
|
|
|
} |
1237
|
|
|
|
1238
|
|
|
if ( $i == $dates['m_end'] ) { |
1239
|
|
|
$num_of_days = $dates['day_end']; |
1240
|
|
|
} else { |
1241
|
|
|
$num_of_days = cal_days_in_month( CAL_GREGORIAN, $i, $y ); |
1242
|
|
|
} |
1243
|
|
|
|
1244
|
|
|
while ( $d <= $num_of_days ) : |
1245
|
|
|
$earnings_stat = give_get_earnings_by_date( $d, $i, $y ); |
1246
|
|
|
$date_key = date( 'Ymd', strtotime( $y . '/' . $i . '/' . $d ) ); |
1247
|
|
|
if ( ! isset( $earnings['earnings'][ $date_key ] ) ) { |
1248
|
|
|
$earnings['earnings'][ $date_key ] = 0; |
1249
|
|
|
} |
1250
|
|
|
$earnings['earnings'][ $date_key ] += $earnings_stat; |
1251
|
|
|
$total += $earnings_stat; |
1252
|
|
|
$d ++; |
1253
|
|
|
endwhile; |
1254
|
|
|
|
1255
|
|
|
$i ++; |
1256
|
|
|
endwhile; |
1257
|
|
|
|
1258
|
|
|
$y ++; |
1259
|
|
|
endwhile; |
1260
|
|
|
|
1261
|
|
|
$earnings['totals'] = $total; |
1262
|
|
|
} else { |
1263
|
|
|
if ( $args['date'] == 'this_quarter' || $args['date'] == 'last_quarter' ) { |
1264
|
|
|
$earnings_count = (float) 0.00; |
1265
|
|
|
|
1266
|
|
|
// Loop through the months |
1267
|
|
|
$month = $dates['m_start']; |
1268
|
|
|
|
1269
|
|
|
while ( $month <= $dates['m_end'] ) : |
1270
|
|
|
$earnings_count += give_get_earnings_by_date( null, $month, $dates['year'] ); |
1271
|
|
|
$month ++; |
1272
|
|
|
endwhile; |
1273
|
|
|
|
1274
|
|
|
$earnings['earnings'][ $args['date'] ] = $earnings_count; |
1275
|
|
|
} else { |
1276
|
|
|
$earnings['earnings'][ $args['date'] ] = give_get_earnings_by_date( $dates['day'], $dates['m_start'], $dates['year'] ); |
1277
|
|
|
} |
1278
|
|
|
} |
1279
|
|
|
} elseif ( $args['form'] == 'all' ) { |
1280
|
|
|
$forms = get_posts( array( 'post_type' => 'give_forms', 'nopaging' => true ) ); |
1281
|
|
|
|
1282
|
|
|
$i = 0; |
1283
|
|
|
foreach ( $forms as $form_info ) { |
1284
|
|
|
$earnings['earnings'][ $i ] = array( $form_info->post_name => give_get_form_earnings_stats( $form_info->ID ) ); |
1285
|
|
|
$i ++; |
1286
|
|
|
} |
1287
|
|
|
} else { |
1288
|
|
|
if ( get_post_type( $args['form'] ) == 'give_forms' ) { |
1289
|
|
|
$form_info = get_post( $args['form'] ); |
1290
|
|
|
$earnings['earnings'][0] = array( $form_info->post_name => give_get_form_earnings_stats( $args['form'] ) ); |
1291
|
|
|
} else { |
1292
|
|
|
$error['error'] = sprintf( __( 'Form %s not found!', 'give' ), $args['form'] ); |
1293
|
|
|
} |
1294
|
|
|
} |
1295
|
|
|
|
1296
|
|
|
if ( ! empty( $error ) ) { |
1297
|
|
|
return $error; |
1298
|
|
|
} |
1299
|
|
|
|
1300
|
|
|
return $earnings; |
1301
|
|
|
} elseif ( $args['type'] == 'donors' ) { |
1302
|
|
|
$customers = new Give_DB_Customers(); |
1303
|
|
|
$stats['donations']['total_donors'] = $customers->count(); |
1304
|
|
|
|
1305
|
|
|
return $stats; |
1306
|
|
|
|
1307
|
|
|
} elseif ( empty( $args['type'] ) ) { |
1308
|
|
|
$stats = array_merge( $stats, $this->get_default_sales_stats() ); |
1309
|
|
|
$stats = array_merge( $stats, $this->get_default_earnings_stats() ); |
1310
|
|
|
|
1311
|
|
|
return array( 'stats' => $stats ); |
1312
|
|
|
} |
1313
|
|
|
} |
1314
|
|
|
|
1315
|
|
|
/** |
1316
|
|
|
* Retrieves Recent Sales |
1317
|
|
|
* |
1318
|
|
|
* @access public |
1319
|
|
|
* @since 1.1 |
1320
|
|
|
* @return array |
1321
|
|
|
*/ |
1322
|
10 |
|
public function get_recent_donations() { |
1323
|
10 |
|
global $wp_query; |
|
|
|
|
1324
|
|
|
|
1325
|
10 |
|
$sales = array(); |
1326
|
|
|
|
1327
|
10 |
|
if ( ! user_can( $this->user_id, 'view_give_reports' ) && ! $this->override ) { |
1328
|
|
|
return $sales; |
1329
|
|
|
} |
1330
|
|
|
|
1331
|
10 |
|
if ( isset( $wp_query->query_vars['id'] ) ) { |
1332
|
|
|
$query = array(); |
1333
|
|
|
$query[] = give_get_payment_by( 'id', $wp_query->query_vars['id'] ); |
1334
|
10 |
|
} elseif ( isset( $wp_query->query_vars['purchasekey'] ) ) { |
1335
|
|
|
$query = array(); |
1336
|
|
|
$query[] = give_get_payment_by( 'key', $wp_query->query_vars['purchasekey'] ); |
1337
|
10 |
|
} elseif ( isset( $wp_query->query_vars['email'] ) ) { |
1338
|
|
|
$query = give_get_payments( array( |
1339
|
|
|
'meta_key' => '_give_payment_user_email', |
1340
|
|
|
'meta_value' => $wp_query->query_vars['email'], |
1341
|
|
|
'number' => $this->per_page(), |
1342
|
|
|
'page' => $this->get_paged(), |
1343
|
|
|
'status' => 'publish' |
1344
|
|
|
) ); |
1345
|
|
|
} else { |
1346
|
10 |
|
$query = give_get_payments( array( |
1347
|
10 |
|
'number' => $this->per_page(), |
1348
|
10 |
|
'page' => $this->get_paged(), |
1349
|
|
|
'status' => 'publish' |
1350
|
10 |
|
) ); |
1351
|
|
|
} |
1352
|
|
|
|
1353
|
10 |
|
if ( $query ) { |
1354
|
10 |
|
$i = 0; |
1355
|
10 |
|
foreach ( $query as $payment ) { |
1356
|
10 |
|
$payment_meta = give_get_payment_meta( $payment->ID ); |
1357
|
10 |
|
$user_info = give_get_payment_meta_user_info( $payment->ID ); |
1358
|
10 |
|
$first_name = isset( $user_info['first_name'] ) ? $user_info['first_name'] : ''; |
1359
|
10 |
|
$last_name = isset( $user_info['last_name'] ) ? $user_info['last_name'] : ''; |
1360
|
|
|
|
1361
|
10 |
|
$sales['donations'][ $i ]['ID'] = give_get_payment_number( $payment->ID ); |
1362
|
10 |
|
$sales['donations'][ $i ]['transaction_id'] = give_get_payment_transaction_id( $payment->ID ); |
1363
|
10 |
|
$sales['donations'][ $i ]['key'] = give_get_payment_key( $payment->ID ); |
1364
|
10 |
|
$sales['donations'][ $i ]['total'] = give_get_payment_amount( $payment->ID ); |
1365
|
10 |
|
$sales['donations'][ $i ]['gateway'] = give_get_payment_gateway( $payment->ID ); |
1366
|
10 |
|
$sales['donations'][ $i ]['name'] = $first_name . ' ' . $last_name; |
1367
|
10 |
|
$sales['donations'][ $i ]['fname'] = $first_name; |
1368
|
10 |
|
$sales['donations'][ $i ]['lname'] = $last_name; |
1369
|
10 |
|
$sales['donations'][ $i ]['email'] = give_get_payment_user_email( $payment->ID ); |
1370
|
10 |
|
$sales['donations'][ $i ]['date'] = $payment->post_date; |
1371
|
|
|
|
1372
|
10 |
|
$form_id = isset( $payment_meta['form_id'] ) ? $payment_meta['form_id'] : $payment_meta; |
1373
|
10 |
|
$price = isset( $payment_meta['form_id'] ) ? give_get_form_price( $payment_meta['form_id'] ) : false; |
1374
|
10 |
|
$price_id = isset( $payment_meta['price_id'] ) ? $payment_meta['price_id'] : null; |
1375
|
|
|
|
1376
|
10 |
|
$sales['donations'][ $i ]['form']['id'] = $form_id; |
1377
|
10 |
|
$sales['donations'][ $i ]['form']['name'] = get_the_title( $payment_meta['form_id'] ); |
1378
|
10 |
|
$sales['donations'][ $i ]['form']['price'] = $price; |
1379
|
|
|
|
1380
|
10 |
|
if ( give_has_variable_prices( $form_id ) ) { |
1381
|
10 |
|
if ( isset( $payment_meta['price_id'] ) ) { |
1382
|
10 |
|
$price_name = give_get_price_option_name( $form_id, $payment_meta['price_id'], $payment->ID ); |
1383
|
10 |
|
$sales['donations'][ $i ]['form']['price_name'] = $price_name; |
1384
|
10 |
|
$sales['donations'][ $i ]['form']['price_id'] = $price_id; |
1385
|
10 |
|
$sales['donations'][ $i ]['form']['price'] = give_get_price_option_amount( $form_id, $price_id ); |
1386
|
|
|
|
1387
|
10 |
|
} |
1388
|
10 |
|
} |
1389
|
|
|
|
1390
|
|
|
//Add custom meta to API |
1391
|
10 |
|
foreach ( $payment_meta as $meta_key => $meta_value ) { |
1392
|
|
|
|
1393
|
|
|
$exceptions = array( |
1394
|
10 |
|
'form_title', |
1395
|
10 |
|
'form_id', |
1396
|
10 |
|
'price_id', |
1397
|
10 |
|
'user_info', |
1398
|
10 |
|
'key', |
1399
|
10 |
|
'email', |
1400
|
10 |
|
'date', |
1401
|
10 |
|
); |
1402
|
|
|
|
1403
|
|
|
//Don't clutter up results with dupes |
1404
|
10 |
|
if ( in_array( $meta_key, $exceptions ) ) { |
1405
|
10 |
|
continue; |
1406
|
|
|
} |
1407
|
|
|
|
1408
|
10 |
|
$sales['donations'][ $i ]['payment_meta'][ $meta_key ] = $meta_value; |
1409
|
|
|
|
1410
|
10 |
|
} |
1411
|
|
|
|
1412
|
10 |
|
$i ++; |
1413
|
10 |
|
} |
1414
|
10 |
|
} |
1415
|
|
|
|
1416
|
10 |
|
return apply_filters( 'give_api_donations_endpoint', $sales ); |
1417
|
|
|
} |
1418
|
|
|
|
1419
|
|
|
/** |
1420
|
|
|
* Retrieve the output format |
1421
|
|
|
* |
1422
|
|
|
* Determines whether results should be displayed in XML or JSON |
1423
|
|
|
* |
1424
|
|
|
* @since 1.1 |
1425
|
|
|
* |
1426
|
|
|
* @return mixed|void |
1427
|
|
|
*/ |
1428
|
|
|
public function get_output_format() { |
1429
|
|
|
global $wp_query; |
|
|
|
|
1430
|
|
|
|
1431
|
|
|
$format = isset( $wp_query->query_vars['format'] ) ? $wp_query->query_vars['format'] : 'json'; |
1432
|
|
|
|
1433
|
|
|
return apply_filters( 'give_api_output_format', $format ); |
1434
|
|
|
} |
1435
|
|
|
|
1436
|
|
|
|
1437
|
|
|
/** |
1438
|
|
|
* Log each API request, if enabled |
1439
|
|
|
* |
1440
|
|
|
* @access private |
1441
|
|
|
* @since 1.1 |
1442
|
|
|
* @global $give_logs |
1443
|
|
|
* @global $wp_query |
1444
|
|
|
* |
1445
|
|
|
* @param array $data |
1446
|
|
|
* |
1447
|
|
|
* @return void |
1448
|
|
|
*/ |
1449
|
|
|
private function log_request( $data = array() ) { |
1450
|
|
|
if ( ! $this->log_requests ) { |
1451
|
|
|
return; |
1452
|
|
|
} |
1453
|
|
|
|
1454
|
|
|
global $give_logs, $wp_query; |
|
|
|
|
1455
|
|
|
|
1456
|
|
|
$query = array( |
1457
|
|
|
'give-api' => $wp_query->query_vars['give-api'], |
1458
|
|
|
'key' => isset( $wp_query->query_vars['key'] ) ? $wp_query->query_vars['key'] : null, |
1459
|
|
|
'token' => isset( $wp_query->query_vars['token'] ) ? $wp_query->query_vars['token'] : null, |
1460
|
|
|
'query' => isset( $wp_query->query_vars['query'] ) ? $wp_query->query_vars['query'] : null, |
1461
|
|
|
'type' => isset( $wp_query->query_vars['type'] ) ? $wp_query->query_vars['type'] : null, |
1462
|
|
|
'form' => isset( $wp_query->query_vars['form'] ) ? $wp_query->query_vars['form'] : null, |
1463
|
|
|
'customer' => isset( $wp_query->query_vars['customer'] ) ? $wp_query->query_vars['customer'] : null, |
1464
|
|
|
'date' => isset( $wp_query->query_vars['date'] ) ? $wp_query->query_vars['date'] : null, |
1465
|
|
|
'startdate' => isset( $wp_query->query_vars['startdate'] ) ? $wp_query->query_vars['startdate'] : null, |
1466
|
|
|
'enddate' => isset( $wp_query->query_vars['enddate'] ) ? $wp_query->query_vars['enddate'] : null, |
1467
|
|
|
'id' => isset( $wp_query->query_vars['id'] ) ? $wp_query->query_vars['id'] : null, |
1468
|
|
|
'purchasekey' => isset( $wp_query->query_vars['purchasekey'] ) ? $wp_query->query_vars['purchasekey'] : null, |
1469
|
|
|
'email' => isset( $wp_query->query_vars['email'] ) ? $wp_query->query_vars['email'] : null, |
1470
|
|
|
); |
1471
|
|
|
|
1472
|
|
|
$log_data = array( |
1473
|
|
|
'log_type' => 'api_request', |
1474
|
|
|
'post_excerpt' => http_build_query( $query ), |
1475
|
|
|
'post_content' => ! empty( $data['error'] ) ? $data['error'] : '', |
1476
|
|
|
); |
1477
|
|
|
|
1478
|
|
|
$log_meta = array( |
1479
|
|
|
'request_ip' => give_get_ip(), |
1480
|
|
|
'user' => $this->user_id, |
1481
|
|
|
'key' => isset( $wp_query->query_vars['key'] ) ? $wp_query->query_vars['key'] : null, |
1482
|
|
|
'token' => isset( $wp_query->query_vars['token'] ) ? $wp_query->query_vars['token'] : null, |
1483
|
|
|
'time' => $data['request_speed'], |
1484
|
|
|
'version' => $this->get_queried_version() |
1485
|
|
|
); |
1486
|
|
|
|
1487
|
|
|
$give_logs->insert_log( $log_data, $log_meta ); |
1488
|
|
|
} |
1489
|
|
|
|
1490
|
|
|
|
1491
|
|
|
/** |
1492
|
|
|
* Retrieve the output data |
1493
|
|
|
* |
1494
|
|
|
* @access public |
1495
|
|
|
* @since 1.1 |
1496
|
|
|
* @return array |
1497
|
|
|
*/ |
1498
|
|
|
public function get_output() { |
1499
|
|
|
return $this->data; |
1500
|
|
|
} |
1501
|
|
|
|
1502
|
|
|
/** |
1503
|
|
|
* Output Query in either JSON/XML. The query data is outputted as JSON |
1504
|
|
|
* by default |
1505
|
|
|
* |
1506
|
|
|
* @since 1.1 |
1507
|
|
|
* @global $wp_query |
1508
|
|
|
* |
1509
|
|
|
* @param int $status_code |
1510
|
|
|
*/ |
1511
|
|
|
public function output( $status_code = 200 ) { |
1512
|
|
|
global $wp_query; |
|
|
|
|
1513
|
|
|
|
1514
|
|
|
$format = $this->get_output_format(); |
1515
|
|
|
|
1516
|
|
|
status_header( $status_code ); |
1517
|
|
|
|
1518
|
|
|
do_action( 'give_api_output_before', $this->data, $this, $format ); |
1519
|
|
|
|
1520
|
|
|
switch ( $format ) : |
1521
|
|
|
|
1522
|
|
|
case 'xml' : |
1523
|
|
|
|
1524
|
|
|
require_once GIVE_PLUGIN_DIR . 'includes/libraries/array2xml.php'; |
1525
|
|
|
$xml = Array2XML::createXML( 'give', $this->data ); |
1526
|
|
|
echo $xml->saveXML(); |
1527
|
|
|
|
1528
|
|
|
break; |
1529
|
|
|
|
1530
|
|
|
case 'json' : |
1531
|
|
|
|
1532
|
|
|
header( 'Content-Type: application/json' ); |
1533
|
|
|
if ( ! empty( $this->pretty_print ) ) { |
1534
|
|
|
echo json_encode( $this->data, $this->pretty_print ); |
1535
|
|
|
} else { |
1536
|
|
|
echo json_encode( $this->data ); |
1537
|
|
|
} |
1538
|
|
|
|
1539
|
|
|
break; |
1540
|
|
|
|
1541
|
|
|
|
1542
|
|
|
default : |
1543
|
|
|
|
1544
|
|
|
// Allow other formats to be added via extensions |
1545
|
|
|
do_action( 'give_api_output_' . $format, $this->data, $this ); |
1546
|
|
|
|
1547
|
|
|
break; |
1548
|
|
|
|
1549
|
|
|
endswitch; |
1550
|
|
|
|
1551
|
|
|
do_action( 'give_api_output_after', $this->data, $this, $format ); |
1552
|
|
|
|
1553
|
|
|
give_die(); |
1554
|
|
|
} |
1555
|
|
|
|
1556
|
|
|
/** |
1557
|
|
|
* Modify User Profile |
1558
|
|
|
* |
1559
|
|
|
* Modifies the output of profile.php to add key generation/revocation |
1560
|
|
|
* |
1561
|
|
|
* @access public |
1562
|
|
|
* @since 1.1 |
1563
|
|
|
* |
1564
|
|
|
* @param object $user Current user info |
1565
|
|
|
* |
1566
|
|
|
* @return void |
1567
|
|
|
*/ |
1568
|
|
|
function user_key_field( $user ) { |
|
|
|
|
1569
|
|
|
|
1570
|
|
|
if ( ( give_get_option( 'api_allow_user_keys', false ) || current_user_can( 'manage_give_settings' ) ) && current_user_can( 'edit_user', $user->ID ) ) { |
1571
|
|
|
$user = get_userdata( $user->ID ); |
1572
|
|
|
?> |
1573
|
|
|
<table class="form-table"> |
1574
|
|
|
<tbody> |
1575
|
|
|
<tr> |
1576
|
|
|
<th> |
1577
|
|
|
<?php esc_attr_e( 'Give API Keys', 'give' ); ?> |
1578
|
|
|
</th> |
1579
|
|
|
<td> |
1580
|
|
|
<?php |
1581
|
|
|
$public_key = $this->get_user_public_key( $user->ID ); |
1582
|
|
|
$secret_key = $this->get_user_secret_key( $user->ID ); |
1583
|
|
|
?> |
1584
|
|
|
<?php if ( empty( $user->give_user_public_key ) ) { ?> |
1585
|
|
|
<input name="give_set_api_key" type="checkbox" id="give_set_api_key" value="0" /> |
1586
|
|
|
<span class="description"><?php esc_attr_e( 'Generate API Key', 'give' ); ?></span> |
1587
|
|
|
<?php } else { ?> |
1588
|
|
|
<strong style="display:inline-block; width: 125px;"><?php _e( 'Public key:', 'give' ); ?> </strong> |
1589
|
|
|
<input type="text" disabled="disabled" class="regular-text" id="publickey" value="<?php echo esc_attr( $public_key ); ?>" /> |
1590
|
|
|
<br /> |
1591
|
|
|
<strong style="display:inline-block; width: 125px;"><?php esc_attr_e( 'Secret key:', 'give' ); ?> </strong> |
1592
|
|
|
<input type="text" disabled="disabled" class="regular-text" id="privatekey" value="<?php echo esc_attr( $secret_key ); ?>" /> |
1593
|
|
|
<br /> |
1594
|
|
|
<strong style="display:inline-block; width: 125px;"><?php esc_attr_e( 'Token:', 'give' ); ?> </strong> |
1595
|
|
|
<input type="text" disabled="disabled" class="regular-text" id="token" value="<?php echo esc_attr( $this->get_token( $user->ID ) ); ?>" /> |
1596
|
|
|
<br /> |
1597
|
|
|
<input name="give_set_api_key" type="checkbox" id="give_set_api_key" value="0" /> |
1598
|
|
|
<span class="description"><label for="give_set_api_key"><?php esc_attr_e( 'Revoke API Keys', 'give' ); ?></label></span> |
1599
|
|
|
<?php } ?> |
1600
|
|
|
</td> |
1601
|
|
|
</tr> |
1602
|
|
|
</tbody> |
1603
|
|
|
</table> |
1604
|
|
|
<?php } |
1605
|
|
|
} |
1606
|
|
|
|
1607
|
|
|
/** |
1608
|
|
|
* Process an API key generation/revocation |
1609
|
|
|
* |
1610
|
|
|
* @access public |
1611
|
|
|
* @since 1.1 |
1612
|
|
|
* |
1613
|
|
|
* @param array $args |
1614
|
|
|
* |
1615
|
|
|
* @return void |
1616
|
|
|
*/ |
1617
|
|
|
public function process_api_key( $args ) { |
1618
|
|
|
|
1619
|
|
|
if ( ! wp_verify_nonce( $_REQUEST['_wpnonce'], 'give-api-nonce' ) ) { |
1620
|
|
|
|
1621
|
|
|
wp_die( esc_attr__( 'Nonce verification failed', 'give' ), __( 'Error', 'give' ), array( 'response' => 403 ) ); |
1622
|
|
|
|
1623
|
|
|
} |
1624
|
|
|
|
1625
|
|
|
if ( empty( $args['user_id'] ) ) { |
1626
|
|
|
wp_die( esc_attr__( 'User ID Required', 'give' ), esc_attr__( 'Error', 'give' ), array( 'response' => 401 ) ); |
1627
|
|
|
} |
1628
|
|
|
|
1629
|
|
|
if ( is_numeric( $args['user_id'] ) ) { |
1630
|
|
|
$user_id = isset( $args['user_id'] ) ? absint( $args['user_id'] ) : get_current_user_id(); |
1631
|
|
|
} else { |
1632
|
|
|
$userdata = get_user_by( 'login', $args['user_id'] ); |
1633
|
|
|
$user_id = $userdata->ID; |
1634
|
|
|
} |
1635
|
|
|
$process = isset( $args['give_api_process'] ) ? strtolower( $args['give_api_process'] ) : false; |
1636
|
|
|
|
1637
|
|
|
if ( $user_id == get_current_user_id() && ! give_get_option( 'allow_user_api_keys' ) && ! current_user_can( 'manage_give_settings' ) ) { |
1638
|
|
|
wp_die( sprintf( __( 'You do not have permission to %s API keys for this user', 'give' ), $process ), __( 'Error', 'give' ), array( 'response' => 403 ) ); |
1639
|
|
|
} elseif ( ! current_user_can( 'manage_give_settings' ) ) { |
1640
|
|
|
wp_die( sprintf( __( 'You do not have permission to %s API keys for this user', 'give' ), $process ), __( 'Error', 'give' ), array( 'response' => 403 ) ); |
1641
|
|
|
} |
1642
|
|
|
|
1643
|
|
|
switch ( $process ) { |
1644
|
|
|
case 'generate': |
1645
|
|
|
if ( $this->generate_api_key( $user_id ) ) { |
1646
|
|
|
delete_transient( 'give-total-api-keys' ); |
1647
|
|
|
wp_redirect( add_query_arg( 'give-message', 'api-key-generated', 'edit.php?post_type=give_forms&page=give-settings&tab=api' ) ); |
1648
|
|
|
exit(); |
|
|
|
|
1649
|
|
|
} else { |
1650
|
|
|
wp_redirect( add_query_arg( 'give-message', 'api-key-failed', 'edit.php?post_type=give_forms&page=give-settings&tab=api' ) ); |
1651
|
|
|
exit(); |
|
|
|
|
1652
|
|
|
} |
1653
|
|
|
break; |
|
|
|
|
1654
|
|
|
case 'regenerate': |
1655
|
|
|
$this->generate_api_key( $user_id, true ); |
1656
|
|
|
delete_transient( 'give-total-api-keys' ); |
1657
|
|
|
wp_redirect( add_query_arg( 'give-message', 'api-key-regenerated', 'edit.php?post_type=give_forms&page=give-settings&tab=api' ) ); |
1658
|
|
|
exit(); |
|
|
|
|
1659
|
|
|
break; |
|
|
|
|
1660
|
|
|
case 'revoke': |
1661
|
|
|
$this->revoke_api_key( $user_id ); |
1662
|
|
|
delete_transient( 'give-total-api-keys' ); |
1663
|
|
|
wp_redirect( add_query_arg( 'give-message', 'api-key-revoked', 'edit.php?post_type=give_forms&page=give-settings&tab=api' ) ); |
1664
|
|
|
exit(); |
|
|
|
|
1665
|
|
|
break; |
|
|
|
|
1666
|
|
|
default; |
1667
|
|
|
break; |
1668
|
|
|
} |
1669
|
|
|
} |
1670
|
|
|
|
1671
|
|
|
/** |
1672
|
|
|
* Generate new API keys for a user |
1673
|
|
|
* |
1674
|
|
|
* @access public |
1675
|
|
|
* @since 1.1 |
1676
|
|
|
* |
1677
|
|
|
* @param int $user_id User ID the key is being generated for |
1678
|
|
|
* @param boolean $regenerate Regenerate the key for the user |
1679
|
|
|
* |
1680
|
|
|
* @return boolean True if (re)generated succesfully, false otherwise. |
1681
|
|
|
*/ |
1682
|
|
|
public function generate_api_key( $user_id = 0, $regenerate = false ) { |
1683
|
|
|
|
1684
|
|
|
if ( empty( $user_id ) ) { |
1685
|
|
|
return false; |
1686
|
|
|
} |
1687
|
|
|
|
1688
|
|
|
$user = get_userdata( $user_id ); |
1689
|
|
|
|
1690
|
|
|
if ( ! $user ) { |
1691
|
|
|
return false; |
1692
|
|
|
} |
1693
|
|
|
|
1694
|
|
|
$public_key = $this->get_user_public_key( $user_id ); |
1695
|
|
|
$secret_key = $this->get_user_secret_key( $user_id ); |
1696
|
|
|
|
1697
|
|
|
if ( empty( $public_key ) || $regenerate == true ) { |
|
|
|
|
1698
|
|
|
$new_public_key = $this->generate_public_key( $user->user_email ); |
1699
|
|
|
$new_secret_key = $this->generate_private_key( $user->ID ); |
1700
|
|
|
} else { |
1701
|
|
|
return false; |
1702
|
|
|
} |
1703
|
|
|
|
1704
|
|
|
if ( $regenerate == true ) { |
|
|
|
|
1705
|
|
|
$this->revoke_api_key( $user->ID ); |
1706
|
|
|
} |
1707
|
|
|
|
1708
|
|
|
update_user_meta( $user_id, $new_public_key, 'give_user_public_key' ); |
1709
|
|
|
update_user_meta( $user_id, $new_secret_key, 'give_user_secret_key' ); |
1710
|
|
|
|
1711
|
|
|
return true; |
1712
|
|
|
} |
1713
|
|
|
|
1714
|
|
|
/** |
1715
|
|
|
* Revoke a users API keys |
1716
|
|
|
* |
1717
|
|
|
* @access public |
1718
|
|
|
* @since 1.1 |
1719
|
|
|
* |
1720
|
|
|
* @param int $user_id User ID of user to revoke key for |
1721
|
|
|
* |
1722
|
|
|
* @return string |
1723
|
|
|
*/ |
1724
|
|
|
public function revoke_api_key( $user_id = 0 ) { |
1725
|
|
|
|
1726
|
|
|
if ( empty( $user_id ) ) { |
1727
|
|
|
return false; |
1728
|
|
|
} |
1729
|
|
|
|
1730
|
|
|
$user = get_userdata( $user_id ); |
1731
|
|
|
|
1732
|
|
|
if ( ! $user ) { |
1733
|
|
|
return false; |
1734
|
|
|
} |
1735
|
|
|
|
1736
|
|
|
$public_key = $this->get_user_public_key( $user_id ); |
1737
|
|
|
$secret_key = $this->get_user_secret_key( $user_id ); |
1738
|
|
|
if ( ! empty( $public_key ) ) { |
1739
|
|
|
delete_transient( md5( 'give_api_user_' . $public_key ) ); |
1740
|
|
|
delete_transient( md5( 'give_api_user_public_key' . $user_id ) ); |
1741
|
|
|
delete_transient( md5( 'give_api_user_secret_key' . $user_id ) ); |
1742
|
|
|
delete_user_meta( $user_id, $public_key ); |
1743
|
|
|
delete_user_meta( $user_id, $secret_key ); |
1744
|
|
|
} else { |
1745
|
|
|
return false; |
1746
|
|
|
} |
1747
|
|
|
|
1748
|
|
|
return true; |
1749
|
|
|
} |
1750
|
|
|
|
1751
|
2 |
|
public function get_version() { |
1752
|
2 |
|
return self::VERSION; |
1753
|
|
|
} |
1754
|
|
|
|
1755
|
|
|
|
1756
|
|
|
/** |
1757
|
|
|
* Generate and Save API key |
1758
|
|
|
* |
1759
|
|
|
* Generates the key requested by user_key_field and stores it in the database |
1760
|
|
|
* |
1761
|
|
|
* @access public |
1762
|
|
|
* @since 1.1 |
1763
|
|
|
* |
1764
|
|
|
* @param int $user_id |
1765
|
|
|
* |
1766
|
|
|
* @return void |
1767
|
|
|
*/ |
1768
|
2 |
|
public function update_key( $user_id ) { |
1769
|
2 |
|
if ( current_user_can( 'edit_user', $user_id ) && isset( $_POST['give_set_api_key'] ) ) { |
1770
|
|
|
|
1771
|
2 |
|
$user = get_userdata( $user_id ); |
1772
|
|
|
|
1773
|
2 |
|
$public_key = $this->get_user_public_key( $user_id ); |
1774
|
2 |
|
$secret_key = $this->get_user_secret_key( $user_id ); |
1775
|
|
|
|
1776
|
2 |
|
if ( empty( $public_key ) ) { |
1777
|
2 |
|
$new_public_key = $this->generate_public_key( $user->user_email ); |
1778
|
2 |
|
$new_secret_key = $this->generate_private_key( $user->ID ); |
1779
|
|
|
|
1780
|
2 |
|
update_user_meta( $user_id, $new_public_key, 'give_user_public_key' ); |
1781
|
2 |
|
update_user_meta( $user_id, $new_secret_key, 'give_user_secret_key' ); |
1782
|
2 |
|
} else { |
1783
|
|
|
$this->revoke_api_key( $user_id ); |
1784
|
|
|
} |
1785
|
2 |
|
} |
1786
|
2 |
|
} |
1787
|
|
|
|
1788
|
|
|
/** |
1789
|
|
|
* Generate the public key for a user |
1790
|
|
|
* |
1791
|
|
|
* @access private |
1792
|
|
|
* @since 1.1 |
1793
|
|
|
* |
1794
|
|
|
* @param string $user_email |
1795
|
|
|
* |
1796
|
|
|
* @return string |
1797
|
|
|
*/ |
1798
|
2 |
|
private function generate_public_key( $user_email = '' ) { |
1799
|
2 |
|
$auth_key = defined( 'AUTH_KEY' ) ? AUTH_KEY : ''; |
1800
|
2 |
|
$public = hash( 'md5', $user_email . $auth_key . date( 'U' ) ); |
1801
|
2 |
|
return $public; |
1802
|
|
|
} |
1803
|
|
|
|
1804
|
|
|
/** |
1805
|
|
|
* Generate the secret key for a user |
1806
|
|
|
* |
1807
|
|
|
* @access private |
1808
|
|
|
* @since 1.1 |
1809
|
|
|
* |
1810
|
|
|
* @param int $user_id |
1811
|
|
|
* |
1812
|
|
|
* @return string |
1813
|
|
|
*/ |
1814
|
2 |
|
private function generate_private_key( $user_id = 0 ) { |
1815
|
2 |
|
$auth_key = defined( 'AUTH_KEY' ) ? AUTH_KEY : ''; |
1816
|
2 |
|
$secret = hash( 'md5', $user_id . $auth_key . date( 'U' ) ); |
1817
|
|
|
|
1818
|
2 |
|
return $secret; |
1819
|
|
|
} |
1820
|
|
|
|
1821
|
|
|
/** |
1822
|
|
|
* Retrieve the user's token |
1823
|
|
|
* |
1824
|
|
|
* @access private |
1825
|
|
|
* @since 1.1 |
1826
|
|
|
* |
1827
|
|
|
* @param int $user_id |
1828
|
|
|
* |
1829
|
|
|
* @return string |
1830
|
|
|
*/ |
1831
|
|
|
public function get_token( $user_id = 0 ) { |
1832
|
|
|
return hash( 'md5', $this->get_user_secret_key( $user_id ) . $this->get_user_public_key( $user_id ) ); |
1833
|
|
|
} |
1834
|
|
|
|
1835
|
|
|
/** |
1836
|
|
|
* Generate the default sales stats returned by the 'stats' endpoint |
1837
|
|
|
* |
1838
|
|
|
* @access private |
1839
|
|
|
* @since 1.1 |
1840
|
|
|
* @return array default sales statistics |
1841
|
|
|
*/ |
1842
|
|
|
private function get_default_sales_stats() { |
1843
|
|
|
|
1844
|
|
|
// Default sales return |
1845
|
|
|
$sales = array(); |
1846
|
|
|
$sales['donations']['today'] = $this->stats->get_sales( 0, 'today' ); |
1847
|
|
|
$sales['donations']['current_month'] = $this->stats->get_sales( 0, 'this_month' ); |
1848
|
|
|
$sales['donations']['last_month'] = $this->stats->get_sales( 0, 'last_month' ); |
1849
|
|
|
$sales['donations']['totals'] = give_get_total_sales(); |
1850
|
|
|
|
1851
|
|
|
return $sales; |
1852
|
|
|
} |
1853
|
|
|
|
1854
|
|
|
/** |
1855
|
|
|
* Generate the default earnings stats returned by the 'stats' endpoint |
1856
|
|
|
* |
1857
|
|
|
* @access private |
1858
|
|
|
* @since 1.1 |
1859
|
|
|
* @return array default earnings statistics |
1860
|
|
|
*/ |
1861
|
|
|
private function get_default_earnings_stats() { |
1862
|
|
|
|
1863
|
|
|
// Default earnings return |
1864
|
|
|
$earnings = array(); |
1865
|
|
|
$earnings['earnings']['today'] = $this->stats->get_earnings( 0, 'today' ); |
1866
|
|
|
$earnings['earnings']['current_month'] = $this->stats->get_earnings( 0, 'this_month' ); |
1867
|
|
|
$earnings['earnings']['last_month'] = $this->stats->get_earnings( 0, 'last_month' ); |
1868
|
|
|
$earnings['earnings']['totals'] = give_get_total_earnings(); |
1869
|
|
|
|
1870
|
|
|
return $earnings; |
1871
|
|
|
} |
1872
|
|
|
|
1873
|
|
|
/** |
1874
|
|
|
* API Key Backwards Compatibility |
1875
|
|
|
* |
1876
|
|
|
* @description A Backwards Compatibility call for the change of meta_key/value for users API Keys |
1877
|
|
|
* |
1878
|
|
|
* @since 1.3.6 |
1879
|
|
|
* |
1880
|
|
|
* @param string $check Whether to check the cache or not |
1881
|
|
|
* @param int $object_id The User ID being passed |
1882
|
|
|
* @param string $meta_key The user meta key |
1883
|
|
|
* @param bool $single If it should return a single value or array |
1884
|
|
|
* |
1885
|
|
|
* @return string The API key/secret for the user supplied |
1886
|
|
|
*/ |
1887
|
38 |
|
public function api_key_backwards_compat( $check, $object_id, $meta_key, $single ) { |
1888
|
|
|
|
1889
|
38 |
|
if ( $meta_key !== 'give_user_public_key' && $meta_key !== 'give_user_secret_key' ) { |
1890
|
38 |
|
return $check; |
1891
|
|
|
} |
1892
|
|
|
|
1893
|
|
|
$return = $check; |
1894
|
|
|
|
1895
|
|
|
switch ( $meta_key ) { |
1896
|
|
|
case 'give_user_public_key': |
1897
|
|
|
$return = Give()->api->get_user_public_key( $object_id ); |
1898
|
|
|
break; |
1899
|
|
|
case 'give_user_secret_key': |
1900
|
|
|
$return = Give()->api->get_user_secret_key( $object_id ); |
1901
|
|
|
break; |
1902
|
|
|
} |
1903
|
|
|
|
1904
|
|
|
if ( ! $single ) { |
1905
|
|
|
$return = array( $return ); |
1906
|
|
|
} |
1907
|
|
|
|
1908
|
|
|
return $return; |
1909
|
|
|
|
1910
|
|
|
} |
1911
|
|
|
|
1912
|
|
|
} |
1913
|
|
|
|
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.